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

# はじめに

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

今回は言語機能やライブラリの強化が多く、非推奨関係の変更がいくつか、といった内容です。
特に新しい標準ライブラリのモジュールが追加されていたりするため、特徴的なものご紹介していきます。

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

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

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

- D言語の更新まとめ 2021年3月版（dmd 2.096.0）
    - https://qiita.com/lempiji/items/df7fc6313247237cde91

# 変更点目次

## コンパイラ変更点

- 曖昧な三項式の非推奨期間が終了し削除されました
- `body` キーワードの使用が非推奨になりました
- インポートを回避するために完全修飾名を使用するケースが非推奨となりました
- 明示的な `package` 可視性属性が新しいスコープに常に適用されるようになりました
- 集成体 (`class`, `struct`, `union`) に `pragma(mangle)` を適用できるようになりました
- 複素数型および虚数型が非推奨となりました
- `while (auto n = expression)` がサポートされました

### 改善点

* Bugzilla 16140: `while(auto x = y)` が `if(auto x = y)` のように動作しません
* Bugzilla 20068: コンストラクタでのユニオン初期化は `@safe` であるべきです
* Bugzilla 21203: 集約型に対する `pragma(mangle)` を受け入れるようにします
* Bugzilla 21585: マングルされた型の文字列を既存の型に変換するために `__traits(totype, string)` を追加します
* Bugzilla 21630: `assert(0)` および `assert(false)` はカバレッジのためにマークされるべきではありません
* Bugzilla 21835: `float` の操作は _x87_ ではなく _XMM_ レジスタを使うべきです

## ランタイム変更点


### 改善点

* Bugzilla 21789: Codecovはファイルのパーミッションにデフォルトの _umask_ を使うべきです

## ライブラリ変更点

- 中央寄せフォーマットが追加されました
- `ImplicitConversionTargets` は非推奨となり、代わりに `AllImplicitConversionTargets` を使用するようになります
- 書式化の際に `%e`、`%f`、`%g`、および `%a` を使って整数型のフォーマットが可能になりました
- `pow(f, -2)` および `f ^^ -2` の実装が変更されました
- `std.format` : `enforceValidFormatSpec` は非推奨となりました
- `std.format` : `formatElement` は非推奨となりました
- `std.format` : `unformatElement` は非推奨となりました
- `FieldNameTuple` は、インターフェースに対して空のタプルを返すようになりました
- `Fields`（旧 `FieldTypeTuple`）は、インターフェースに対して空のタプルを返すようになりました
- コンパイル時に浮動小数点数をフォーマットすることができるようになりました
- 浮動小数点数をフォーマットすると、GCでの割り当てが行われなくなりました
- `std.format` で、一部の `real` 型は `double` にダウンキャストされます
- `std.typecons.Nullable` : 非推奨のエイリアスである `alias get this` が削除されました
- `std.format` のドキュメントが完全に作り直されました
- `std.format` モジュールがより小さなモジュールに分割されました
- `std.math` モジュールがより小さなモジュールに分割されました
- `splitWhen` が `std.algorithm.iteration` に追加されました
- `std.datetime` にあった古いベンチマーク機能が削除されました
- `std.exception.enforceEx` が削除されました
- 新しいモジュールとして `std.sumtype` が追加されました
- `std.range.Transposed` : 非推奨のメンバーである `save` が削除されました

### 改善点

* Bugzilla 13595: `std.algorithm.groupBy` が非等価関係をサポートするよう拡張する
* Bugzilla 16200: 整数指数に対するより高速な `pow` の実装（訳注、Revertされているようなのでこれは含まれていません）
* Bugzilla 18024: `checkedint.Abort` および `checkedint.Warn` は `@safe` であるべきです
* Bugzilla 18627: `std.complex` は、組み込みの複素数型よりも数値計算がかなり遅い
* Bugzilla 20756: `ImplicitConversionTargets` がインターフェースの継承を無視します
* Bugzilla 21759: `std.experimental.checkedint.Checked` は、`"%d"` および `"%x"` 整数フォーマット指定子と互換性がありません
* Bugzilla 21760: `std.conv.to` は文字列を `std.experimental.checkedint.Checked!T` に変換する方法を知りません
* Bugzilla 21761: `Checked!T` が共有されている場合、`std.experimental.checkedint.Checked!T.toHash` を呼び出し可能にします
* Bugzilla 21808: `std.format` : AAのキーと値の順序を変更できるようにすべきです
* Bugzilla 21847: `std.format` : `%e`, `%g`, `%a` を整数でもサポートすべきです
* Bugzilla 21858: `std.format` : 出力を中央寄せにします

## DUB 変更点

- `dub` の設定ファイルに省メモリコンパイルのオプションが追加されました

# 注目トピック

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

### 変更 : 明示的な `package` 可視性属性が新しいスコープに常に適用されるようになりました

複数指定された場合の `package` アクセス保護属性の動作が少し変わりました。

`package` 属性には、アクセス可能なパッケージ範囲を `package(foo.bar) void hoge();` といった具合で指定できますが、これがブロック指定などで複数重なった場合の挙動が変わります。

以下のような例がありますが、正直そこまで影響があるものではなさそうです。

```d
package (foo.fuga): // 以降の定義は foo.fuga からのみアクセスできる

package (foo) void test(); // foo 全体からアクセスできるよう直接指定されている
```

今までは、ブロック指定と直接指定をすべて見て、より細かい設定が優先されていました。
今回からは、直接指定されたほうが優先されるようになります。

この例の場合、 `package (foo) void test()` は指定通りに `foo` モジュール全体から参照可能になります。
こちらのほうが定義だけ見れば良いのでわかりやすいですね。

### 強化 : 集成体 (`class`, `struct`, `union`) に `pragma(mangle)` を適用できるようになりました

今回の変更は、主に C++ との連携で使用するマングリング指定のためのものです。

C++ で定義されたシンボルは、D から見ると C++ 流にマングリングされた名前になっています。
これを D から正しくリンクするには、定義された名前とは別にマングリングされたシンボル名を教えてやる必要があります。

そこで、この変更が効いてくるのが `std::function` など、D言語的にキーワードになっている定義です。

今回の強化を受けて、たとえば以下のように `pragma(mangle)` を指定することができるようになります。
少し特殊な例ですが、`std::function` あたりが使えるようになると、一気に多くの C++ ライブラリが直接リンクできるようになりそうですね。

```d
extern(C++, "std")
{
    template std_function(F)
    {
        pragma(mangle, "function")
        class std_function
        {
            // member variables and functions
        }
    }
}

template ScopeClass(C , string name)
{
    enum ns = __traits(getCppNamespaces,C);
    extern(C++, class) extern(C++,(ns))
    {
        pragma(mangle, C, name)
        struct ScopeClass
        {
            char[__traits(classInstanceSize, C)] buffer;
            // member variables and functions
        }
    }
}

alias FuncType = void function(int);
alias RawFuncType = typeof(*FuncType.init);
// Mangles as `void funk(std::function<void(int)> a)`
extern(C++) void funk( ScopeClass!(std_function!(RawFuncType)),"function") a );
```


### 強化 : `while (auto n = expression)` がサポートされました

こちらは構文的な強化です。

元々 `if` 文では `if (auto n = expression)` といった形で条件式のところに変数宣言が置けました。
何かポインタ変数を宣言して、有効ならそれを使って何かをする、といった用途でよく見るパターンです。

そして今回の強化により、`while (auto n = expression)` というまったく同じ形で変数宣言が書けるようになりました。
ツリー形式のデータで親を辿っていくとか、リンクリストみたいなデータ構造の実装で上手く使えそうですね。

ちなみにこれは ChangeLog の抜粋ですが、実質以下の糖衣構文となっています。なるほど、という感じでした。

```d
while (true)
{
    if (auto n = expression)
    { /* loop body */ }
    else
    { break; }
}
```

## ライブラリ変更点

非常に盛沢山なので、少し内容が薄いのはご容赦を。

### 変更 : `pow(f, -2)` および `f ^^ -2` の実装が変更されました

`-2` 乗ということで、$\frac{1}{x^2}$ に限定された変更です。

元々の実装にバグがあり、入力値によっては最下位ビットに誤りがあったということです。

厳密に最下位ビットにまで依存するコードは少ないかと思われますが、`std.math` の `isClose` などを使い、できるだけ厳密値に依存しない実装としていただければ、といったところです。


### 変更 : `FieldNameTuple` は、インターフェースに対して空のタプルを返すようになりました

`std.traits` には、任意の型に対してフィールドのメンバー名を取り出す `FieldNameTuple` というテンプレートがあります。

これをインターフェース型に適用したとき、コンパイル時に生成される内部型が読み取られることがあった、ということでそれらが読み取れないように挙動が変更されています。

具体的にどのようなケースがあったのかは調べ切れませんでしたが、新しい実装では単に `AliasSeq!()` と空のタプルが返されるようです。


### 変更 : `Fields`（旧 `FieldTypeTuple`）は、インターフェースに対して空のタプルを返すようになりました

前述の `FieldNameTuple` と同様ですので省略します。

### フォーマット処理の強化

今回かなり大規模な更新がありました。
新しい書式化文字列の追加、パフォーマンスの改善、挙動の変更と盛りだくさんです。

#### 強化 : 中央寄せフォーマットが追加されました

数値など桁指定可能なフォーマットに対し、実際の桁が足りていない場合は中央寄せできる機能が増えました。

`%8d` としていたところ、以下のように `=` 記号を書き足して `%=8d` とすると中央寄せになります。

```d
assert(format!"|%=8d|"(1234) == "|  1234  |");
```

また、値が奇数桁になるような場合は1桁左にずらしたくなるようなことがあります。
これは `%=-8d` と書くと1桁左に詰まります。 

```d
assert(format!"|%=-8d|"(123) == "|  123   |");
assert(format!"|%=8d|"(123) ==  "|   123  |");
```

公式のサンプルでも意識されていそうですが、Markdownのテーブルなど生成するのが大変楽になりそうですね。
1回文字列化して桁数を調べたりなど、面倒なパディング計算が不要になるだけでもすごくありがたい気がします。


#### 強化 : 書式化の際に `%e`、`%f`、`%g`、および `%a` を使って整数型のフォーマットが可能になりました

`%e`, `%f`, `%g`, `%a` は浮動小数点数に対する書式化文字列です。

以前は `%f` などの指定に整数型を渡すとエラーになっていたものが、今後は普通に表示されるようになります。

```d
assert(format!"%.3e"(ulong.max) == "1.845e+19");
assert(format!"%.3,3f"(ulong.max) == "18,446,744,073,709,551,615.000");
assert(format!"%.3g"(ulong.max) == "1.84e+19");
assert(format!"%.3a"(ulong.max) == "0x1.000p+64");
```

こちらも `auto` で型が変わりやすいところで `%f` など指定しておけば良いのでプログラミングしやすくなって良いですね。


#### 強化 : コンパイル時に浮動小数点数をフォーマットすることができるようになりました

なりました！

これが地味に嬉しいのは `std.format` だけでなく `std.conv` の `to` や `text` にも影響するところです。

今までコンパイル時処理が難しかったソースコード生成や定数埋め込みの部分も楽に書けるようになる見込みが出てきますね。


#### 改善 : 浮動小数点数をフォーマットすると、GCでの割り当てが行われなくなりました

一連の強化の一環で、GC割り当てが削減されました。

未だ残っているのは例外割り当ての部分です。
逆に言えば、 `format!"%d"("TEST")` といった感じでテンプレート引数にして、コンパイルエラーにしてしまえば問題は起きません。

ちなみにGCを使わない例外については、延期されている [DIP1008](https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1008.md) にて作業中の課題となっています。

#### 変更 : `std.format` で、一部の `real` 型は `double` にダウンキャストされます

`std.format` は内部的に libc の `snprintf` が呼び出されていましたが、これが D で書かれた浮動小数点数のフォーマット用ルーチンに置き換えられました。

これらの関数は、`double`、`64-bit-reals`、`80-bit-reals (x87-reals)` に対してのみ動作します。

つまり、主要なプラットフォームではありませんが、これ以外の `real` 型の実装に対しては `double` にダウンキャストして実行されるため出力精度が低下する可能性がある、ということです。

多くの方に影響はありませんが、特殊な環境であれば注意が必要です。

#### 改善 : `std.format` のドキュメントが完全に作り直されました

後述のモジュール分割に伴い、いくつかの点でドキュメントの見直しが行われました。

主に文法を最新版に合わせて集成、書式化文字列に関する説明の改善、例の追加、の3点です。

構成はそこまで変わらないので以前と同じように読めるかと思います。

- `std.format`
    - https://dlang.org/phobos/std_format.html

### 変更 : モジュールが分割されました

`std.format` と `std.math` モジュールが大きくなってきていたため、より小さなモジュールに分割されました。

細かく見ると、以下のようなサブモジュールに分割されています。

- `std.format`
    - `std.format.spec`
        - フォーマット文字列に関するシンボル（`FormatSpec` 構造体や `singleSpec` テンプレートなど）
    - `std.format.read`
        - 入力の読み取りに関するシンボル（`formattedRead` テンプレートや `unformatValue` テンプレートなど）
    - `std.format.write`
        - 出力の書き込みに関するシンボル（`formattedWrite` テンプレートや `formatValue` テンプレートなど）
- `std.math`
    - `std.math.constants`
        - 数学定数（主に `PI` など）
    - `std.math.algebraic`
        - 基本的な代数関数（主に `abs` や `sqrt` など）
    - `std.math.trigonometry`
        - 三角関数（主に `sin` や `cos` など）
    - `std.math.rounding`
        - 丸めに関する関数（主に `ceil` や `floor` など）
    - `std.math.exponential`
        - 指数関数および対数関数（主に `pow`、`exp` や `log`）
    - `std.math.remainder`
        - 剰余に関する関数（主に `fmod` など）
    - `std.math.operations`
        - 浮動小数点数の操作（主に `isClose`、`nextUp` や `fmin`）
    - `std.math.traits`
        - 浮動小数点の性質に関するもの（主に `isNaN` や `isSubnormal`）
    - `std.math.hardware`
        - ハードウェア制御に関するもの（主に `IeeeFlags` や `FloatingPointControl`）

ちなみに、今まで通り `import std.format` や `import std.math` といった呼び出しは可能なので、使い勝手が変わることはありません。

それぞれ `package.d` というモジュールの仕組みに従っており、 `std/format/package.d` や `std/math/package.d` パスのファイルから、個々のサブモジュールを `public import` することで互換性が維持されています。

参考 : https://dlang.org/spec/module.html#package-module


### 強化 : 新しいモジュールとして `std.sumtype` が追加されました

今回の目玉となる強化です。

元々サードパーティ製のライブラリであった `sumtype` という便利ライブラリが標準に取り込まれました。

この `sumtype` というのは文字通り「型の和」ということで、 `A or B or C` のような「いずれかの型を含めることができる型」を作り出す機能を表しています。

ざっくり使い方としては以下のようになります。

```d
import std.sumtype;

alias Value = SumType!(long, double, string);

Value v = 10;
v.match!(
    (long n) { writeln("long!"); },
    (double v) { writeln("double!"); },
    (string s) { writeln("string!"); },
);
```

使い方については以下の記事にまとめてありますので、こちら見ていただければと思います。

- 安全なunion、SumTypeの紹介と使い方
    - https://qiita.com/lempiji/items/80a1e83cb661f573856b

### 強化: `splitWhen` が `std.algorithm.iteration` に追加されました

`std.algorithm` の一部として、`splitWhen` というテンプレート関数が追加されました。

これは、1つの前方レンジ(Forward Range)に対して分割位置を判定するための条件を渡し、複数のレンジに分割する関数です。

このテンプレート関数には、2つの要素を受け取り分割位置で `true` を返すような関数を指定します。

例を見ていただくとわかりやすいです。

```d
import std.algorithm.comparison : equal;
import std.range : dropExactly;

auto source = [4, 3, 2, 11, 0, -3, -3, 5, 3, 0];

auto result1 = source.splitWhen!((a,b) => a <= b);
assert(result1.save.equal!equal([
    [4, 3, 2],
    [11, 0, -3],
    [-3],
    [5, 3, 0]
]));
```

また、これは元々あった `chunkBy` とほぼ同じ動きですが、`chunkBy` で指定する述語はもう少し厳しい条件があります。
一方、`splitWhen` のほうは `Forward Range` を要求しますが、述語部分の条件が緩いので扱いやすくなっています。

今後どちらを使えば良いというものではなく、`splitWhen` でダメなら `chunkBy` にしてみる、といった使い分けになってきます。
どちらでも動くようなら速度計測をしたほうが良いかもしれませんね。


その他、どのように条件が厳しいのかは詳しくは `chunkBy` のドキュメントを確認してください。

- `std.algorithm.iteration.chunkBy`
    - https://dlang.org/phobos/std_algorithm_iteration.html#chunkBy

## DUB変更点

### 強化 : `dub` の設定ファイルに省メモリコンパイルのオプションが追加されました

コンパイル時のメモリ消費を抑えるため、DMD や LDC でサポートされる `-lowmem` というフラグを既定で有効にする設定が追加されました。

これは DUB が持つ `settings.json` という設定ファイルで `defaultLowMemory` というキーを設定することで有効にできます。

```json
{
    "defaultLowMemory": true
}
```

`settings.json` の内容については以下に説明があります。

- DUB _settings.json_
  - https://dub.pm/settings

また、`settings.json` は以下のパスに置かれているものを認識するようになっています。

__Windows__

- `%ProgramData%\dub\settings.json`
- `<dub executable folder>\..\etc\dub\settings.json`
- `%APPDATA%\dub\settings.json`
- `%ROOT_PACKAGE_DIR%\dub.settings.json`

__Linux__

- `/var/lib/dub/settings.json`
- `<dub executable folder>/../etc/dub/settings.json`
- `~/.dub/settings.json`
- `$ROOT_PACKAGE_DIR/dub.settings.json`

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

今回新たに非推奨となる機能は7点、また以前から非推奨だった機能が5つ廃止されます。
色々あってリリース期間があいているのもあり、大規模アップデートといった様相ですが、正直そこまで影響が大きいものはほとんどありません。

__非推奨__

- `body` キーワードの使用が非推奨になりました
- インポートを回避するために完全修飾名を使用するケースが非推奨となりました
- 複素数型および虚数型が非推奨となりました
- `ImplicitConversionTargets` は非推奨となり、代わりに `AllImplicitConversionTargets` を使用するようになります
- `std.format` : `enforceValidFormatSpec` は非推奨となりました
- `std.format` : `formatElement` は非推奨となりました
- `std.format` : `unformatElement` は非推奨となりました


__削除__

- 曖昧な三項式の非推奨期間が終了し削除されました
- `std.typecons.Nullable` : 非推奨のエイリアスである `get this` が削除されました
- `std.datetime` にあった古いベンチマーク機能が削除されました
- `std.exception.enforceEx` が削除されました
- `std.range.Transposed` : 非推奨のメンバーである `save` が削除されました


### 非推奨 : `body` キーワードの使用が非推奨になりました

この `body` キーワードは、関数の事前条件や事後条件で使う `in` と `out` に対し、関数本体などの実装部分を表すときにマーカーとなるキーワードでした。
やや今更感がある方もいるかもしれませんが、これは2016年に受理された [DIP1003](https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1003.md) という改善提案を受けたものです。

たとえば以下のように使われます。

```d
void sqrt(float x)
in // ここから事前条件
{
    assert(x >= 0);
}
out(y) // ここから事後条件
{
    assert(isClose(y * y, x));
}
body // ここから実装
{
    // impl
}
```

この `body` という命名が様々な外部ライブラリで構造体のメンバーなどに使われやすく、ヘッダー変換時などで微妙だと前々から言われていました。

そして今回ついに非推奨に踏み切った格好になります。

これは代わりに `do` キーワードで代替できるようになっています。

```d
viud sqrt(float x)
in
{
    assert(x > 0);
}
do // body の代わりに do が利用できる
{
    // impl
}
```

### 非推奨 : インポートを回避するために完全修飾名を使用するケースが非推奨となりました

何のことかというと、モジュールを `import` していなくても完全修飾名を使うと `import` 済みかのように扱える機能が非推奨になった、というものです。

割と大穴なので以前にも似たような問題が修正されたのですが、今回も似たようなパターンです。
例としては以下のようになります。

```d
import std.algorithm;

// v2.071で非推奨となり、v2.084でエラーとなったパターンです
auto n = std.range.Take!(int[]); // Error: undefined identifier `range` in package `std`...

// 今回はこのような用法が非推奨となります。 v2.106 からエラーになる予定です。
std.range.Take!(int[]) s;
```

`import std.algorithm` しか書かれていないのに、`std.range.Take` を使おうとしているので何かおかしいですね。
このような場合は普通に `import` したりすべきです。

ちなみにエラーメッセージに `static import` を使うべき、というメッセージが出るのでそれに従えばOKです。


### 非推奨 : 複素数型および虚数型が非推奨となりました

D言語には組み込みの複素数型がありました。純虚数型の `ifloat` や複素数型の `cdouble` などです。

今後は標準ライブラリの `std.complex` を使うべきということで、そちらを利用しましょう。

個人的には `1 + 2i` と書けたり大変好きだったんですが、コンパイラに入れるメリットが少ないという感じでしょうか。
長らく検討されていた内容でもあるので仕方なし、といったところです。

### 非推奨 : `std.format` : `enforceValidFormatSpec` は非推奨となりました

元々公開する意図のない関数が誤って公開されていた、というものです。
v2.107.0にて削除される予定です。

こちら何か便利で汎用的な関数でもなく、ドキュメントにも無いので特に言うことはない感じです。

### 非推奨 : `std.format` : `formatElement` は非推奨となりました

こちらも元々公開する意図のない関数が誤って公開されていた、というものです。
v2.107.0にて削除される予定です。

ドキュメントにも記載はないのですが、便利関数であるため代替方法が例示されています。

公式サンプルを少し調整していますが、以下のようになります。

```d
// formatElement(sink, value, fmt); としていたコードの代替例

import std.range : only, put;

.put(sink, format!("%("~fmt~"%)")(only(value)));
```


### 非推奨 : `std.format` : `unformatElement` は非推奨となりました

こちらも元々公開する意図のない関数が誤って公開されていた、というものです。
v2.107.0にて削除される予定です。

ドキュメントにも記載はないのですが、便利関数であるため代替方法が例示されています。

文字や文字列に対しては `std.conv` にある `parseElement` を使い、それ以外のケースについては `std.format.read` の `unformatValue` を用いれば良いとのことです。


### 削除 : 曖昧な三項式の非推奨期間が終了し削除されました

~~みんなが大好き~~批判の的になりがちな、三項演算子と代入の組み合わせパターンで出てくる警告になるケースが廃止されました。

v2.082.0 (2018-09-01) から警告になっていて、括弧を付けるよう言われるので、多くの人はあまり気にしていないかと思われます。

曖昧な例としてあるのが以下のものです。

```d
true ? stt = "AA" : stt = "BB"
```

さて、これは「一見 `if` 文に見える」という意地の悪いサンプルですが、文法的に括弧を補うと以下のようになります。

```d
(true ? (stt = "AA") : stt) = "BB"
```

ちょっと読みづらいですが、要するに必ず "BB" になってしまう、という驚きの結果になります。

CやC++でも同じであり許容されるコードなので認められていましたが、今後エラーを見かけたら適切に括弧を補うようにしましょう。


__エラー例__

ちなみにエラーが出ると以下のようになります。

```console
Error: `b ? stt = "AA" : stt` must be surrounded by parentheses when next to operator `=`
```

2番目の `=` の前までで切り取られてしまっているので何か変だと気づけますね。
適切に括弧で囲みなさいと怒られます。


### 削除 : `std.typecons.Nullable` : 非推奨のエイリアスである `alias get this` が削除されました

今回の削除の中でも割と影響の大きなポイントです。

`std.typecons.Nullable` はいわゆる `Optional` などと呼ばれる「値がないことを示せるようにする型」です。
クラスに対する `null` と同じような意味合いで名づけられていますが、それをより安全に使えるようにしたのが今回の `Nullable` です。

さて、今回はこの `Nullable` で提供されていた `alias get this` という暗黙変換に関わる宣言が取り除かれました。

これがどういう影響を与えるかというと、以下のようなコードがコンパイルできなくなります。

```d
void foo(int n) { }

import std.typecons : Nullable;

Nullable!int n = null;

foo(n); // 引数に Nullable!int を渡している
```

このサンプルに対し、今までは以下のような警告が出ていました。

```console
onlineapp.d(11): Deprecation: function `std.typecons.Nullable!int.Nullable.get_` is deprecated - Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.
```

関数呼び出しのところで `.get` を使いなさいと言われます。
言われた通りに直すと警告が消えます。

```d
foo(n.get());
```

さらに言えば、`.get` は値が `null` だった場合に例外を発生させるので、事前に値が `null` かどうかをチェックしてから呼び出します。

```d
if (!n.isNull) {
    foo(n.get());
}
```

やや手間ですが、これでバッチリ安全ですね。


### 削除 : `std.datetime` にあった古いベンチマーク機能が削除されました

v2.077.0 から非推奨となっていた `std.datetime` のベンチマーク機能(`StopWatch` など)が削除されました。

しかしこちら通常利用の範囲では特に対応の必要はありません。

というのも、 `std.datetime.stopwatch` というモジュールに同名の定義があり、`import std.datetime` だけして使っている場合はこちらも読み込まれ、ほぼ同じ記述で動くように配慮されているためです。

時期にして約2年前から警告になっていますので、目にしたら直接 `std.datetime.stopwatch` などに書き換えていたかと思いますが、今後は特に気にしなくて良くなります。


### 削除 : `std.exception.enforceEx` が削除されました

これは v2.079 から非推奨となっており、代わりに `std.exception.enforce` を使うことが推奨されています。


### 削除 : `std.range.Transposed` : 非推奨のメンバーである `save` が削除されました

`std.range.Transposed` というのは2次元配列を転置したかのように扱うことができるレンジです。

削除された `save` というメンバーは、レンジの状態をコピーして残すためのもので、通常の `InputRange` に加えてこの `save` があると `ForwardRange` と呼ばれます。

この `Transposed` というレンジは内部に持つレンジを透過的に操作するタイプのレンジであるため、一度進めたレンジを一時保存することができません。

今まで特に警告が出ていなかった方は特に関係ありませんが、もしエラーが出るようであれば `save` を使わないように書き換える必要があります。


# まとめ

予定していた2ヶ月おきのリリースルールから少しずれ込み、3ヶ月あけてのリリースとなりました。

今回はフォーマット系の強化や `sumtype` の追加、モジュール分割などの比較的大規模な修正がまとめて入れられており、ここ数年では大規模なリリースの1つとなったのではないかと思います。

また、今回は利用できるようになっていませんが裏ではC言語連携の強化が行われており、次回も話題に事欠かないリリースとなりそうです。

次回のリリース予定は 2021/08/01 とのことです。
夏真っ盛りかと思いますが、期待して待ちたいと思います！