Dlang-TourでD言語を少し勉強したメモ

# これはなにか
- 2017年は新しい言語をゼロから勉強してなかったことを思い出したので、D言語を[Dlang-Tour](https://tour.dlang.org/)で少しだけ勉強してみたのでその記録です。
- 自分用のメモを雑多にまとめたので読みづらいです。ごめんなさい。

# Dlang-tourを一通り読んで手元で動かしてみた所感
- 自分はc++よりもjavaの方が経験が長いのだが `とてもjavaっぽいc` という印象を受けた。特にclassの定義はjavaと殆ど同じ。
- 最近の言語っぽく、oopも関数型スタイルもこなすマルチパラダイムな言語でありながらメモリ管理をマニュアルで出来たりと守備範囲がめっちゃ広い
- 一方で、守備範囲広すぎて、どういう用途が向いているのかパッと分からないという気もした。dlangじゃないとこれができない！というのが、自分の勉強不足が理由でまだ分かってないせいかもしれないけど…
- とはいえ、速度を求める場合やメモリ制限が厳しい場合に、バイナリをシュッと出力できるモダンでシンプルな言語がほしい時にはいいかもしれない。組み込みとか、あとは競プロにも良さそう。

# なぜD言語なのか
- いつも利用してる図書館でたまたま見つけた[プログラミング言語D](https://www.amazon.co.jp/dp/4798131105/)を勉強の息抜きで読んでみたら、思ったよりとっつきやすかったので勉強してみようと思った

# 学習記録
## [officialサイトのトップページに書いてある宣伝文句](https://dlang.org/)を読んで雑に訳した
- 概要
    - D言語は多目的プログラミング言語だよ
    - 静的型付け、システムレベルアクセス、Ｃっぽいシンタックス
    - 安全性とプログラマーの生産性によって、効率性とコントロールとモデリングを併せ持つよ
- なんでDなの
    - 利便性
        - Dは動的言語のように冗長な型を書かずにでかいコードが書けるよ
        - 一方で、静的インターフェースが型やプロパティを推論するので、静的世界と動的世界の良いとこどりが出来るよ
        - 自動メモリ管理によって安全でシンプルで堅牢なコードにするよ
        - Dはscoped resource managementとscope statementをサポートし、書きやすくて読みやすい決定論的トランザクションコードが書けるよ [^1]
        - 線形および連想配列、slice、rangeがあるので、日々のプログラミングタスク（小さなものから大きなものまで）をシンプルかつ楽しいものにするよ
    - パワー
        - Dはクラシックなポリモーフィズム、値セマンティクス、関数スタイル、ジェネリクス、汎用プログラミング、契約プログラミング等を提供し、それらは全て調和を保ちつつ統合されているよ
        - Dは並行性に対する革新的なアプローチを提供するよ。そのための機能として、真のイミュータブルなデータ、メッセージパッシング、デフォルトでの非共有性、複数スレッド間の真の不変データ共有管理を特徴としているよ。
        - シンプルなスクリプトから大規模なプロジェクトにいたるまで、Dは、ユニットテスト、情報隠蔽、洗練されたモジュール性、高速コンパイル、正確なインタフェースなど、アプリケーションのニーズに応じて幅広く拡張できるよ
    - 効率性
        - Dのコードは自然と効率性の高いネイティブコードにコンパイルされるよ
        - Dは大抵の「明確」なコードが速く、そして安全になるようにデザインされているよ
        - 時には、速度と制御のために、型安全の境界から逃げる必要があるかもしれないけど、そのようなレアケースに備えて、Dはポインタ、型変換、C関数アクセス、手動メモリ管理、独自のアロケーター、インラインアセンブリコードを提供するよ
           

## [Dlang tour](https://tour.dlang.org/)の最初の方を読んでみる
- まずはinstall。
- EditorはVisual Studio Codeに[D Language Extension](https://marketplace.visualstudio.com/items?itemName=dlang-vscode.dlang)を入れて使う。

```shell-session
$ brew install dmd
```

- package managerである `dub` を使ってprojectのtemplateが作れるらしいのでやってみる。

```shell-session
$ brew install dub
$ dub init hello
dub init hello
Package recipe format (sdl/json) [json]:
Name [hello]:
Description [A minimal D application.]:
Author name [KazuhiroSerizawa]:
License [proprietary]:
Copyright string [Copyright © 2017, KazuhiroSerizawa]:
Add dependency (leave empty to skip) []:
Successfully created an empty project in '/Users/seri/Documents/d-work/hello'.
Package successfully created in hello

$ cd hello
$ tree .
.
├── dub.json
└── source
    └── app.d
```

`app.d` の中身は

```d
import std.stdio;

void main()
{
        writeln("Edit source/app.d to start your project.");
}
```

実行するにはprojectの直下で `dub run` で良いようだ。 ( `dub` だけでもcompileされて実行された）

```shell-session
$ dub run
Performing "debug" build using dmd for x86_64.
hello ~master: target for configuration "application" is up to date.
To force a rebuild of up-to-date targets, run again with --force.
Running ./hello
Edit source/app.d to start your project.
```

[^1]: サンプルコードを読んだ感じだとクロージャを書けるよってことらしい

### moduleについて

- dmdコンパイラに付随する標準ライブラリは[Phobos](https://dlang.org/phobos/)という名称がついている
- Phobosのnamespaceは `std` 。c++と同じか。
- `import` キーワードでモジュールを読み込んで使えるようにする

```d
import std.stdio;
```

- 読み込むシンボルを選択的に限定することもできる

```d
import std.stdio : writeln, writefln;
```

- import句はファイルのトップにも書けるが、関数の中にも書ける

```d
void main(){
    import std.stdio : writln;
    writeln("Hello World!");
}
```

### moduleのpathについて

- dのnamespaceはファイル階層と一致しており、例えば `import my.cat` で検索されるのは `my/cat.d` である
- 何も指定しない場合、暗黙的にimportを実行するscriptのcurrent directoryを起点としてmoduleを検索する
- moduleを検索する起点となるdirectoryを指定するにはコンパイル時に `-I` オプションでdirectoryを指定する
- また指定したmoduleがファイルではなくdirectoryの場合コンパイラはそのdirectory配下の
 `package.d` というファイルをロードしようとする
    - pythonの `__init__.py` みたいなもんだろうか 

#### 余談：Dlang tourの日本語版に `package.d` を使うpath指定についての解説が入ってなかったのでPR出した
- [githubにソースがあるので](https://github.com/dlang-tour/japanese/blob/master/basics/imports-and-modules.md)これを修正してPR出せばいいっぽい
- importで指定したmoduleの参照先がdirectoryだった場合、package.dを自動でloadする機構は[2.064](https://dlang.org/changelog/2.064.html)で入った比較的新しい機能らしく、英語版は今年の6月に[追加されている](https://github.com/dlang-tour/english/pull/181/files)が日本語版の追加が漏れてるっぽい
- 後日、日本語版のrepositoryにPRを出して無事マージされた https://github.com/dlang-tour/japanese/pull/90

### 基本型
- dlangの基本型は`bool` , `byte`, `ubyte`, `char` `short`, `ushort`, `wchar`, `int`, `uint`, `dchar`, `long`, `ulong`, `float`, `double`, `real`
- 文字列は `char` がUTF-8、 `wchar`がUTF-16、 `dchar` がUTF-32に対応でそれぞれ使われるらしい
- 型が異なる変数間の型変換は精度に影響しなければ許可される
- 強制的な型変換には `cast` を使う
- `auto`キーワードによって型推論ができる。 `auto myVar = 7;` だと `myVar` の型を `int`と推測する
- 全てのデータ型は、初期値となる値を `.init` プロパティとして保持している。 `int.init` だと `0`、 `float.init` だと `nan` を返す。

### Memory管理
- dlangもポインタ演算ができる
- syntaxはc, c++と大体同じだが、mallocの代わりに `new` 演算子が使える
- GCがあるのでnewした変数は自分でfreeしなくてもいい

```d
int a;
int* b = &a;
auto c = &a; // aのアドレス
int *a = new int; // cで言うところの `malloc(sizeof(int))` に該当する？
```

- dlangは３つのセキュリティレベルがある。 `@system`, `@trusted`, `@safe`
- デフォルトは `@system`
- `@safe` はメモリ破壊を防ぐためのdのサブセットであり、 `@safe` なコードは `@safe` または `@trusted` な関数のみ呼び出せるよう制限し、ポインタ演算を禁止したりする

```dlang
void main() @safe
{
	import std.stdio;
	writeln("Edit source/app.d to start your project.");
	int a = 5;
	int* p = &a;
	int* c = p + 5;
}
```
コレを実行すると以下のエラーメッセージが出る

```
Error: cannot take address of local a in @safe function main
Error: pointer arithmetic not allowed in @safe functions
```

### 可変性
- javaやc++でいうところの `final`に該当する `immutable` という型修飾子がある
- カレントスコープでのみ有効となる `const` もある

```d
immutable int err = 5;
err = 6;
```

```
Error: cannot modify immutable expression err
```

### 関数定義
- よくある感じ

```d
int add(int lhs, int rhs) {
    return lhs + rhs;
}
```

- 関数の返り値も `auto` で推論できる

```d
auto add(int lhs, int rhs) {
    return lhs + rhs;
}
```

### 配列
- 普通の静的配列、動的配列がある
- 動的配列はスライスとも呼ばれ、range指定でデータの一部の参照を取り出すことができる

```d
int[8] arr1; // 静的配列
int[] arr2 = new int[8]; // 動的配列
int[] arr3 = [1, 2, 3, 4, 5];
auto arr4 = arr3[1 .. $]; // スライスはrange指定で要素の参照(≠値コピー)を取り出せる
writeln(arr4); //=> [2,3,4,5];
```

### foreach
- dにはLLにはおなじみのforeachがある

```d
foreach (int e; arr) {
    writeln(e);
}

foreach (i, e; [4, 5, 6]) { // iにはindexが格納される
    writeln(i, ":", e);
}
```

### 連想配列
- いわゆるHash

```d-objdump
int[string] hash;
hash["hogetarou"] = 1;
hash["fugatarou"] = 2;
writeln(hash["hogetarou"]); // 1
```

### クラス
- scopeの意味はjavaやc++と同じ模様

```d
class Any {
    protected string type;
    
    // constructor
    this(string type) {
        this.type = type;
    }

    // finalは継承を禁止する
    final string getType() {
        return type;
    }

    // private
    private string hoge() {
        return "hoge";
    }

    // 継承して実装しないと使えない
    // abstractな関数が一個でもあるとnewできないabstract class扱いになる模様
    abstract string convertToString(); 
}
```

## 次はこれ読む
[プログラミング言語D](https://www.amazon.co.jp/dp/B00G9QJ74O/)
![IMG_20171104_225459.jpg](https://qiita-image-store.s3.amazonaws.com/0/7174/f5419e10-5fe0-55f1-03a1-7e747003047a.jpeg)