D言語の更新まとめ 2020年3月版（dmd 2.091.0）

# はじめに
D言語の公式コンパイラである dmd が更新され、最新バージョンである `2.091.0` が 2020/03/08 にリリースされました。（ChangeLogの日付によります）

今回はWindows関連とC++連携の強化が多く行われており、ボリュームも結構あるので目立つトピックをメインにまとめたいと思います。

より細かい内容は下記リンクからChangeLogをご覧ください。

- ChangeLog
    - https://dlang.org/changelog/2.091.0.html

また、前回1月ののリリースまとめは以下になります。

- D言語の更新まとめ 2020年1月版（dmd 2.090.0）
    - https://qiita.com/lempiji/items/17cd436fdd991bf1c2d6

# 変更点目次

## コンパイラ変更点
- クラスアロケーター/デアロケーターが削除されました。
- GNUエラースタイルのレポートがサポートされました。
- 試験的に `extern(C|C++)` からC++ヘッダーを生成する機能が追加されました。


### 改善点
* Bugzilla 20569: [DIP1000] `scope` 修飾された構造体のフィールドが参照でなければアドレスを取得できるようになります。
    * https://issues.dlang.org/show_bug.cgi?id=20569

## ランタイム変更点
- いくつかの環境に対して `pthread_attr_destroy` が追加されました。
- `core.sys.windows.security` の定義が展開、拡充されました。
- `core.stdcpp.memory.unique_ptr` が追加されました。
- `TFD_TIMER_CANCEL_ON_SET` が追加されました。

### 改善点
* Bugzilla 20146: `std.bigint.BigInt` から組み込みの浮動小数点数へのキャストを許可します。
* Bugzilla 20480: `std.getopt` が `DIP 1000` で利用できるようにします。
* Bugzilla 20548: `RandomCover`で1ワードに収まらないとき、`bool[]` の代わりにビットベクトルを使うようにします。
* Bugzilla 20566: `std.sformat` では浮動小数点数の出力時にメモリ割り当てを避けるべきです。
    * `std.format`の間違い？

## ライブラリ変更点
- `std.bigint` が `@safe` になりました。
- `std.math` にて `approxEqual` が `isClose` に置き換えられました。
- 非推奨だった `std.format.Mangle` が削除されました。
- 非推奨だった `std.stdio` の構造体、 `ByLine`, `ByChunk`, `ByRecord` が削除されました。
- 非推奨だった `std.string` の関数がいくつか削除されました。
- `std.algorithm.sorting.schwartzSort` が2引数関数による変換がサポートされました、 
- `std.functional` に `curry` が追加されました。

### 改善点
* Bugzilla 19218: `object.destroy` はクラスの静的配列をチェックすべきです。
* Bugzilla 20550: GCで使うtreapのため固定のシードを使うようにします。
* Bugzilla 20567: 単純なプログラムにおいて、GCの並列マーキングのためにスレッドを開始するべきではありません。
* Bugzilla 20577: Windows UACに関するシンボルを追加します。
    * 主に `sdkddkver.h`に相当する内容が `core.sys.windows.sdkddkver` に追加された

## インストーラー変更点
- インストールスクリプトがWindowsで動作するようになりました。
- リリースされた `dmd.exe` は `LDC` でビルドされ、コンパイル時間が30%から40%改善されます。
- `dmd.exe` と `lld-link.exe` の64-bit版のビルドが `bin64` フォルダに追加されました。
- 付属のWindowsライブラリと定義が `MinGW 5.0.2` から `MinGW 7.0.0` に変更されました。（ワイド文字列のmainエントリポイントの追加と共に）
    * 翻訳が怪しいです
- Windowsバイナリに付属しているLLDリンカは、9.0.0（例外がWin32上で動作するようにするパッチを含む）にアップグレードされました。
- MinGWインポートライブラリにリンクされているVCランタイムが `msvcr120.dll` にアップグレードされました(最新バージョンは、単純なコピーを可能にし、汎用Cランタイムに依存しません)。再配布可能なDLLは、追加のインストーラを実行しなくてもすぐに使用できるように、それぞれのbinフォルダに追加されています。
- `curl` のライブラリとDLLは `7.68` に更新されました。
- 古い `windbg.exe` が削除されました。
- インストーラはVS2019のインストールを検知するようになりました。VCのインストールが見つからない場合、提案されるダウンロードはVS2017ではなくVS2019になります。

※ChangeLog上「the couple of updates」としてまとめられていたものもこちらで一覧にしました

## DUB変更点
- 環境変数として `SOURCE_FILES` が追加されました。
- zshの補完が追加されました。

# 注目トピック
## 言語・コンパイラ変更点
### 強化：GNUのエラースタイルが利用可能になった

コンパイル結果に表示されるエラー報告で、GNUのエラースタイルが利用可能になりました。

これによって既存のIDEと互換性が高まるなどが期待されています。

具体的な形式としては、 `filename:line[:column]: message` となり、使うには `-verror-style=gnu` と指定します。

（あんまり変わってないような…？）

### 試験的：C/C++向けのヘッダーが生成可能になった

今回のリリースの目玉となっている強化です。

`extern(C)` や `extern(C++)` というリンケージが付いている宣言に対し、`-HC` や `-HCf=<file>`、`-HCd=<directory>` というフラグを付けるとC++向けのヘッダーが生成できるようになりました。

元々D言語自体がC++からの移行を考えて作られていることもあり、既存システムをDで置き換えていく、という目標に対して重要なマイルストーンの1つとなっています。

既存システムの書き換えとして、大きく以下2つの方向性があるわけですが、今回前者が強化された格好になります。

1. C++で書かれたシステムに対し、部品の一部をDで書き直す（表面がC++、中身はD）
2. C++で書かれたシステムから部品を抜き出し、Dで書かれたシステムから利用する（表面がD、中身はC++）

どんなものが変換されヘッダーが生成されるのか、ChangeLogを抜粋してくると以下のようになっています。

```d:a.d
module a;

extern(C) int foo(int a) { ... }
extern(C++) void bar() { ... }
void ignored() { ... }
```

```d:b.d
module b;

extern (C++) struct S
{
    string name;
    this (string name) { ... }
    bool bar() { ... }
}
```

```d:c.d
module c;

import a, b;

extern (C++) class C
{
    S[] s;
    this () {}
    bool bar() { ...}
}
```

これを `dmd -c -o- -HC a.d b.d c.d` でコンパイルすると下記が生成されます。

```cpp:
#pragma once

// Automatically generated by dmd -HC

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

#define _d_void void
#define _d_bool bool
#define _d_byte signed char
#define _d_ubyte unsigned char
#define _d_short short
#define _d_ushort unsigned short
#define _d_int int
#define _d_uint unsigned
#define _d_long long long
#define _d_ulong unsigned long long
#define _d_float float
#define _d_double double
#define _d_real long double
#define _d_char char
#define _d_wchar wchar_t
#define _d_dchar unsigned
typedef _d_long d_int64;
#define _d_null NULL

// Parsing module a
// Parsing module b
// Parsing module c
struct S;
extern "C" _d_int foo(_d_int a);

extern _d_void bar();

// ignoring function a.ignored because of linkage
struct S
{
    DArray< _d_char > name;
    S(DArray< _d_char > name);
    _d_bool bar();
    S() : name() {}
};

class C
{
public:
    DArray< S > s;
    C();
    virtual _d_bool bar();
};
```

`#define` が多いのはそういうものとして、結構無難に生成されている感じでしょうか？（DArrayの定義はどこ…？）

`#pragma once` を使うあたり今風のような気もしますが、機械的に生成するなら普通のインクルードガードでも良いような気がしつつ、将来的にフラグで切り替えられるようになるかもしれません。

試験的な機能なので今後に期待です。

## ランタイム変更点

### 強化： `core.stdcpp.memory.unique_ptr` が追加された

されました。

以前から継続しているC++連携強化施策の1つです。

C++のライブラリでも `unique_ptr` はよく出てくるので、これでまた1つ壁を乗り越えた、という感じですね。
`std::vector` や `std::string` は以前対応されたので、これで移植できるライブラリがかなり増えそうです。

個人的に「内部実装を考えると移植厳しすぎない？」と思っていたので、無事に実現されて一安心です。

`compressed_pair` と呼ばれるフィールドを持たない構造体に対する最適化イディオムまでサポートされており、こういうのもDでちゃんと対応できるんだな、というのがとても勉強になります。

- 参考ソース
    - https://github.com/dlang/druntime/blob/master/src/core/stdcpp/xutility.d#L345

## ライブラリ変更点

### 強化： `std.bigint` が `@safe` に対応した

なぜ今まで対応してなかったの？というと、実装優先だったことと内部的にインラインアセンブラを使っている箇所が多かったからです。（インラインアセンブラは無条件にsafeにできない）

大半は `@safe` の追加なのですが、 何か所か `@trusted` を使い、即時関数の呼び出しを用いる変更が入っています。

```d:before
r.data = cast(immutable) subInt(x.data, y);
```
```d:after
r.data = (() @trusted => cast(immutable) subInt(x.data, y))();
```

- 参考ソース
    - https://github.com/dlang/phobos/commit/5ad491a451122bf660f2c4a65559312c1757324e#diff-69862ea3ea8be2c899af81ae04777a64R662

`@trusted` は「機械的には保証されないが信用されたコード」という意味で、こうすると動作は変えずに多くの式を `@safe` の中で呼び出すことができます。

ライブラリの改善で `@safe` を付けるという話は結構あるので、こういったイディオムとして覚えておくといつか役立つかもしれません。

### 変更：`std.math` の中で `approxEqual` を `isClose` に置き換え

浮動小数点数を適切に比較するため、新しく `isClose` テンプレート関数が追加されました。

浮動小数点数の比較には元々 `approxEqual` テンプレート関数がありましたが、より良い初期値と引数対称性を持っていることが追加理由となっているようです。

今後のリリースで `approxEqual` は非推奨（deprecated）となり、最終的には廃止される予定となっていますが、利用側としては特に書き換えの必要はありません。
（deprecatedにする必要もない気がしますが…）

また、`approxEqual(a, b)` は `isClose(a, b, 1e-2, 1e-2)` でほぼ置き換えが可能とのことですが、誤差指定がない場合は `isClose(a, b)` での書き換えが推奨されています。
（多分 `isClose(a, b, 1e-2, 1e-5)` の間違いです）

#### `approxEqual` と `isClose` の違い

`approxEqual` と `isClose` は共に、相対誤差が一定以下 or 絶対誤差が一定以下、という条件をチェックします。
相対誤差と絶対誤差は第3引数と第4引数でそれぞれ指定します。

違いの1点目は絶対誤差の初期値で、 `isClose` の初期値は絶対誤差が `0.0` となります。
これによって表面的には相対誤差の結果のみを考慮するようになります。

引数の対称性については、相対誤差の基準値を第2引数から算出しているという意味のようで、詳細は以下の記事が参考になります。

- 浮動小数点数の比較で許容する相対誤差と絶対誤差
    - https://qiita.com/mono_shoo/items/61a1951b205ea6aedd25

`isClose` は第1引数から算出した相対誤差も考慮されるため、以下のように `isClose` だけOKになるケースが出てくるようです。

```d:
real a = 100.1;
real b = 100;
    
real maxRelDiff = 0.0009995; // 相対誤差の上限
    
writeln(approxEqual(a, b, maxRelDiff)); // false
writeln(isClose(a, b, maxRelDiff)); // true
```

とまぁ精度が重要であれば、相対誤差と絶対誤差を両方指定して使ったり、保証される値域を確認してみたりすると良いのではないかと思われます。

#### 名前について

余談ですが、2020年3月10日現在、Google翻訳ほかいくつかのサービスでは概ね `X is close to Y` で「XはYに近い」、`X approx equal to Y` のほうを「XはYにほぼ等しい」と訳してくれます。

`isClose` という名前自体はPythonから取っているようですが、個人的には数学的な意味で `approxEqual` のほうが適切だったのかなと思われ、今後 `isClose` が推奨されるのはちょっと複雑な気持ちです。


### 強化：`std.algorithm.sorting` の `schwartzSort` で2引数の変換関数をサポート

これだけ見てもなんのことやらという感じですが、`schwartzSort` 自体は「配列の各要素に対して1度だけ計算を施し、その結果をもってソートする」という関数です。

この計算をする関数は、元々 `a => heavyFunc(a)` といった感じで何か重い処理をする1引数関数が想定されていました。

今回これに「インデックスを第2引数に受け取る2引数関数」が指定できるようになります。

試しに使うと以下の通りで、インデックスは初期状態の位置が指定されます。
これによって、配列の位置によって優先度をつけたり、一定範囲のみ別の計算結果を利用したり、といった切り分けが可能になります。

```d:ソース
import std;

struct S {
    int n;
}

void main() {
    S[] ss;
    foreach (i; 0 .. 10)
    {
        ss ~= S(10 - i);
    }
    
    // 要素をa、インデックスをiで受け取る
    schwartzSort!((a, i) {
        writeln(i, " : ", a);
        return a.n;
    }, "a < b")(ss);
}
```


```console:結果
0 : S(10)
1 : S(9)
2 : S(8)
3 : S(7)
4 : S(6)
5 : S(5)
6 : S(4)
7 : S(3)
8 : S(2)
9 : S(1)
```


### 強化：`std.functional` に `curry` を追加

関数をカリー化する `curry` テンプレート関数が追加されました。

関数型プログラミングの文脈ではよく出てくるカリー化ですが、メタプログラミングの練習で似たようなライブラリがたくさんあると思います。
今回標準ライブラリに追加されたので簡単に使えるようになりました。きっと良いことだと思われます多分。

と、関数呼び出しができるものであれば構造体でも対応しており、以下のような感じで使えます。
こういう関数が増えて楽しく開発できるようになると良いですね。

```d:
import std.functional : curry;

struct S
{
    int w;
    int opCall(int x, int y, int z)
    {
        return w + x + y + z;
    }
}

S s;
s.w = 5;

auto cs = curry(s);
auto cs1 = cs(1);
auto cs2 = cs(2);

assert(cs1(2)(3) == s(1, 2, 3));
assert(cs1(2)(3) == (1 + 2 + 3 + 5));
assert(cs2(2)(3) == s(2, 2, 3));
```


## インストーラー変更点

### 強化：インストールスクリプトがWindows上で動作するようになった

公式のインストールスクリプト（ https://dlang.org/install.sh ）が `CygWin` や `Msys2` などのPOSIX-Likeな環境から利用できるようになった、という強化です。

Windowsではあまり使われなかったインストールスクリプトですが、これで大体の環境から統一された方法でDMDやLDC、dubなどがインストールできるようになりました。

ちなみにWindows 10なら、PowerShellから `Get-PackageProvider Chocolatey` および `Install-Package dmd` とすればほぼ自動でインストールできるので、バージョン切り替えなどを使わなければこれで十分なのでは？という気もします。


### 速度改善

DMDは元々DMD自身でコンパイルして配布（セルフホスト）されていますが、今回のリリースではLDCを使ったバイナリになるようです。

元々速かったコンパイルが更に30%から40%改善するだろうとのことで、速度に関してはかなり期待できそうです。


### 付属のライブラリ更新

リンカの`LLD` や VCランタイム、`curl` といった付属品の多くがバージョンアップされました。

今回が1つの節目となるかと思われますので、何かアプリを作っている方は1度動作確認をしておくほうが良いかと思われます。

使う側としては、まとめて更新されると検証が少なくて良いので楽ですね。


## 非推奨または廃止される機能

### 廃止された機能

今回は追加の非推奨なし、削除された機能が4件です。

- クラスアロケーターが削除されました。
    - 詳細： https://dlang.org/changelog/2.080.0.html#deprecate_class_allocators
- 非推奨だった `std.format.Mangle` が削除されました。
    - `std.demangle.demangle` で代用できます。
- 非推奨だった `std.stdio` の構造体、 `ByLine`, `ByChunk`, `ByRecord` が削除されました。
    - それぞれ `byLine`, `byChunk`, `byRecord` という関数で代用できます。
- 非推奨だった `std.string` の関数がいくつか削除されました。
    - `inPattern`, `countchars`, `removechars`, `squeeze`, `munch` が削除されました。
        - コードは完全に除去され、今後はこういった関数をまとめておくUndeaDというパッケージに置かれます
        - https://code.dlang.org/packages/undead

# まとめ

追加の非推奨は無し、言語機能の強化は限定的、とかなり落ち着いている状況ですが、Windows周りを含め周辺強化が目立ったリリースではないかと思います。

特にWindows民としてはインストーラーの改善が目立つ部分で、UAC周りのシンボル追加があったことを踏まえると、かなり消費者向けのアプリ作成やそういった開発者層にまで裾野が広がってきたのかなと感じます。

C++連携の強化も含め、以前から考えられていた強化案がかなり具体化してきていますし、今後は所有権関連の強化も予定されています。

次回リリース予定は5月、引き続きの強化に期待したいと思います！