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

# はじめに

D言語の公式コンパイラである dmd が更新され、最新バージョンである `2.096.0` が 2021/03/11 にリリースされました。

今回は言語機能やコンパイラ周りの強化、非推奨関係の変更が多く、ランタイムや標準ライブラリ周りの変更は控えめとなっています。
いくつかちょっと面白い機能も出てきているので特徴的なものご紹介していきます。

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

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

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

- D言語の更新まとめ 2021年1月版（dmd 2.095.0）
    - https://qiita.com/lempiji/items/03f29c09fd237a994ba7

# 変更点目次

## コンパイラ変更点

- `x86_64 Posix` をターゲットとした D ABI を変更（訳注：`creal` の扱いについてのみでそこまで大きな話ではありません）
- `__c_complex_float`、`__c_complex_double`、`__c_complex_real` の型を追加
- コピーコンストラクターと自動生成されるPostblitコンストラクタを持つことは非推奨になります
- DMDのJSON出力に常に保護レベルが含まれるようになります
- DMDのJSON出力で [shared] モジュールコンストラクタ/デストラクタが異なる型を持つようになります 
- ローカルな `template` がローカルシンボルを `alias` で受け取る動作が非推奨になります
- C++ヘッダー生成が改善されます
- DMDコンパイラに `-gdwarf=<version>` スイッチが追加されます
- `getProtection` のエイリアスとして `__traits(getVisibility, Sym)` が導入されます
- プレーンな `synchronized` 文は、実行時に割り当てられるミューテックスを使用するようになります
- 単一式からなる関数に対し、短縮記法による実装を許可するようになります

### 改善点

* Bugzilla 7176: 関数とメソッドに対するラムダの `=>` 構文
* Bugzilla 10445: ベクトル型に対する `.min` や `.max` などのプロパティを追加
* Bugzilla 19632: [SIMD] Error: 不正な foreach の集約
* Bugzilla 20788: 色付きと色なしの出力が異なる
* Bugzilla 21527: SIMDコードにおける不必要なメモリへのストア
* Bugzilla 21593: 書き込まれるファイルがすでに存在する場合、ファイルの時刻のみ更新する


## ランタイム変更点

- druntime のオプションである `callStructDtorsDuringGC` が削除されました
- `mount` に属する `statvfs` の FreeBSD 宣言が削除されました
- 実験的な `llvm-libunwind` ベースのバックトレース表示が追加されました

### 改善点

* Bugzilla 14790: カバレッジのマージでは、変更されたソースコードを検出すべきです


## ライブラリ変更点

- `std.math` の `approxEqual` は非推奨になります

### 改善点

* Bugzilla 21523: Microsoft Windows の `std.stdio.File.lock()`, `tryLock()`, `unlock()`: 不要なエラーメッセージにはメモリを割り当てない
* Bugzilla 21559: 非ワイド文字列に対する `walkLength` を高速化します
* Bugzilla 21629: std.csv が空の入力に対して 1 つのレコードを出力する
* Bugzilla 21638: `std.typecons.RefCounted!(T, RefCountedAutoInitialize.no)` が `T.this()` に`@disable` とアノテーションされていても動作するようになります


## DUB 変更点

- DMDでリンカーに使われる `dflags` を追加します
- `copyFiles` を VisualD のプロジェクトで使用できるようになりました

# 注目トピック

## 言語・コンパイラ変更点

### 強化: `__c_complex_float`、`__c_complex_double`、`__c_complex_real` の型を追加

C/C++連携の強化施策の一環です。

C言語には、 `float _Complex` `double _Complex` `long double _Complex` という複素数型があり、これとABI互換性を保つための型が追加される、という強化です。

Dに元からある組み込み複素数型の `cfloat` `cdouble` `creal` が廃止予定となっているので、これらの代わりに今後使っていく型ということになります。
（組み込み型は単にこれらのaliasとなる…？）


### 強化: DMDコンパイラに -gdwarf=<version> スイッチが追加されます

DWARFのシンボリックデバッグ情報を出力するスイッチが追加されます。

サポートされるバージョンは 3、4、5 で、追加すると `-g` スイッチが暗黙的に有効になります。
DWARF バージョン 5 は実験的なサポートとのことです。

`dmd -gdwarf=4 app.d` といった感じで利用します。

DWARFというデバッグ情報が ELF というゲーム機やLinux等のフリーOS向けバイナリ形式に付属するものであるため、このフラグもWindows以外のマシンのみ有効というフラグになっています。
（DWARFという名前自体、ファンタジーに出てくるエルフとドワーフが由来とのこと）


### 実験的機能: 単一式からなる関数に対し、短縮記法による実装を許可するようになります

改善点にもある「関数とメソッドに対するラムダの `=>` 構文」と同じ内容です。
将来的に仕様として採用することを目指し、別の項目にまとめて実験的機能として公開しています。

この機能は、 `-preview=shortenedMethods` というスイッチが追加され、指定されると以下のような記述ができるようになるものです。

```d:同じ意味
int foo() { return 1; }
int foo() => 1;
```

ついに文法が今風？になってきた感がありますね。

関数型の匂いもしますが、C#もこれと同じようなことができるので、案外由来はそちらかもしれません。

参考 : https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members

近年は様々な言語が他の言語と足並み揃える傾向が強いので、学習曲線の低さが売りのD言語としても追従すべきポイントになってきているのかな、といった印象です。


## ライブラリ変更点

### 改善: 非ワイド文字列に対する `walkLength` を高速化します

今回の高速化ネタです。

`walkLength` は一般的なレンジの長さを得る関数で、文字列含めて様々なものにとりあえず使っておけばOKという便利なものです。

今回は12文字程度の短い文字列でも最低2.8倍、2000文字程度になると最低4.2倍、最大10倍超となかなかの高速化です。
計測結果については以下プルリクエストにまとめられているので、興味のある方は見てみてください。

https://github.com/dlang/phobos/pull/7755



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

今回も新たに非推奨となる機能は3点、また以前から非推奨だった機能が2つ廃止されます。
前回も非推奨が2点、削除が1件という状況だったので、まだ整理が続いているな、といった感じです。

__非推奨__

- コピーコンストラクターと自動生成されるPostblitコンストラクタを持つことは非推奨になります
- ローカルな `template` がローカルシンボルを `alias` で受け取る動作が非推奨になります
- `std.math` の `approxEqual` は非推奨になります


__削除__

- druntime のオプションである `callStructDtorsDuringGC` が削除されました
- `mount` に属する `statvfs` の FreeBSD 宣言が削除されました

### 非推奨 : コピーコンストラクターと自動生成されるPostblitコンストラクタを持つことは非推奨になります

コピーコンストラクター関連の機能なので、かなりガッツリ使い込んでいる人でないと引っかからないかもしれません。

これがどのようなコードで警告が出るようになるかというと以下のようなパターンです。

```d:
// Postblitコンストラクタを持つ型
struct A
{
    this(this) {}
}

// 新しくコピーコンストラクターを持つ型を作った
struct B
{
    A a;
    this(const scope ref B) {}
}
```

ここで、型Bの定義自体に以下のような警告が出ます。

```console:
app.d(13): Deprecation: `struct B` implicitly-generated postblit hides copy constructor.
app.d(13):        The field postblit will have priority over the copy constructor.
app.d(13):        To change this, the postblit should be disabled for `struct B`
```

メッセージの内容は「構造体Bは暗黙的に生成されるPostblitコンストラクターがコピーコンストラクターを隠蔽しているよ」というものです。
更に言えば、コピーコンストラクターを書いてるけど呼ばれないから気を付けてね、という意味ですが、なんでそうなるのかちょっと疑問ですね。

今回の場合、型Aが `this(this) {}` の定義を持っているので、言語的には型Bのコピー時もそれが呼び出されるのが正しかろう、という前提があります。
しかしコピーコンストラクターを優先して呼ぶと、中でそれが呼び出される保証はありません。
そこでコピーコンストラクターが追加された当初は、Aの postblit コンストラクタがある場合、それが必ず呼び出されるようBにも `this(this) {}` を自動生成してそれを呼び出すようにしよう、という判断になっていました。

つまり、この警告を見かけた場合、コピーコンストラクターを持つ型のフィールドに `this(this) {}` を持つ型が紛れ込んでいる可能性があるということです。

対応はちょっとややこしいですが、Postblit自体珍しい機能ではあるので、より優位なコピーコンストラクターに書き換えるのが理想的かなと思います。


### 非推奨 : ローカルな `template` がローカルシンボルを `alias` で受け取る動作が非推奨になります

これは元々 DMD 2.087.0 で追加された機能強化で、ローカル変数などを使いローカルで定義したテンプレートやメンバーテンプレートをインスタンス化することができる、というものでした。
しかし、この実装は GDC および LDC のバックエンドと互換性がありませんでした。

実装間で機能の互換性を保つために、この強化は非推奨となり、将来の DMD のリリースで削除される可能性があります。

ちなみにDMDでセーフ、LDCでエラー、という例を挙げると以下のようなものがあります。


```d:
import std;

void main()
{
    int n = 100;
    auto t = new Test;
    auto s = t.toText!n;
    writeln(s);
}

class Test
{
    string toText(alias obj)()
    {
        return to!string(obj);
    }
}
```

DMDで便利に使っていた方もいるかもしれませんが、LDCで動かないかもしれない、ということで無難に引数渡し等を検討する必要があります。


### 非推奨 : `std.math` の `approxEqual` は非推奨になります

以前 `isClose` が追加されたときに記事を書いたので、ざっくりはこちらご覧ください。

https://qiita.com/lempiji/items/85d73a79368ea26ffb58#%E5%A4%89%E6%9B%B4stdmath-%E3%81%AE%E4%B8%AD%E3%81%A7-approxequal-%E3%82%92-isclose-%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88

対応としては、多くの場合 `approxEqual` を `isClose` に一括置換しておけばOKです。

もしテストが通らない箇所があったりした場合、保証精度の指定が必要になります。

`a.approxEqual(b)` に対しては `a.isClose(b, 1e-2, 1e-5)` としておけばほぼ同じ結果になるはずです。


### 削除 : druntime のオプションである `callStructDtorsDuringGC` が削除されました

2019年8月のDMD 2.088.0で非推奨となっていたフラグが削除されました。

実行時にGCの動きを切り替えるフラグで、GCの破棄処理の際に構造体のデストラクタを呼ばないようにする、という特殊フラグです。（用途が良く分かっていません…）

たとえば以下のようにして使っていた場合、これが効かなくなるということですのでご注意ください。

`--DRT-callStructDtorsDuringGC=0`

### 削除 : `mount` に属する `statvfs` の FreeBSD 宣言が削除されました

2018年9月のDMD 2.082.0で非推奨となっていた定義が削除されました。

削除となった定義は `core.sys.freebsd.sys.mount` に定義されていた `statvfs` 関数です。

代わりの定義は `core.sys.posix.sys.statvfs` にありますので、こちらを import しておけば大丈夫です。

# まとめ

久しぶりに目立った文法強化となる実験的機能が入りつつ、非推奨機能の追加などで機能の整理が始まった印象です。
とはいえ無理のない範囲ではありますので、罠のあるような機能は削る方向で進んでもらいたいですね。

書きたいと思ったことがスッと書ける言語、ということで、これからもこういった強化に期待したいと思います。

次回は 5/1 の予定で、また別の機能が実験的なフラグと共に使えるのではないかと思います。
期待して待ちたいと思います！