11
4

More than 1 year has passed since last update.

D言語の更新まとめ 2023年8月版(dmd 2.105.0)

Last updated at Posted at 2023-08-26

はじめに

D言語の公式コンパイラである dmd が更新され、最新バージョンである 2.105.0 が 2022/08/02 にリリースされました。

今回は前回からほぼ2ヶ月でのリリースで、内容はValgrindというメモリチェックツール連携の目玉を中心に、利便性の改善が多い印象です。
今回も一通りの内容ご紹介していきます。

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

また、前回である6月版のリリースまとめは以下になります。

変更点目次

コンパイラ変更点

  • alias this に代入スタイルの構文が許可されるようになりました。
  • catch 節は、const または mutable な例外のみを取る必要があります。
  • 関数は enum ストレージクラスの指定ができなくなりました。
  • extern(C) 関数をオーバーロードすることはエラーになりました。
  • public メソッドでオーバーロードされた private メソッドへのアクセスは非推奨フェーズが終了しました。
  • 事前定義されたバージョン識別子 VisionOS が追加されました。

改善点

  • Bugzilla 4663: static の位置に関する誤ったエラーメッセージ
  • Bugzilla 15436: コンパイラがまだ AliasSeq を"tuple"として参照している(TypeTupleも同様か?)
  • Bugzilla 23475: Windows上で ulong / long を使用した printf の非推奨メッセージが分かりにくい
  • Bugzilla 23871: ImportC: __attribute が認識されない
  • Bugzilla 23877: ImportC: byteswap.h のインポートにより、core.bitop.byteswap への未定義の参照が生じる
  • Bugzilla 23886: ImportC プリプロセッサディレクティブ `#ident`` はサポートされていません
  • Bugzilla 23928: エラーメッセージの改善: スコープ変数sは、abcを呼び出す非スコープパラメータに割り当てられています
  • Bugzilla 23931: エラー: ローカル変数 this を非スコープメンバ関数 this.this() で参照しています
  • Bugzilla 23948: __FILE__ および __MODULE__ は、デフォルトのパラメータとして const(char)* に暗黙的に変換することはできません
  • Bugzilla 23971: C++リンケージを持つスライスを返そうとする際のエラーメッセージをより明確にする
  • Bugzilla 24000: Error: matching } expected, not End of File で "{" の位置を表示する
  • Bugzilla 24023: エラーメッセージのタイプに不要なモジュール接頭辞

ランタイム変更点

変更点

  • druntime に Linux input ヘッダの翻訳が追加されました。
  • ガベージコレクタに Valgrind memcheck ツールの統合が追加されました。

改善点

  • Bugzilla 23980: OpenBSD: unistd.dgetthrname(2)setthrname(2) を追加します
  • Bugzilla 24044: 配列の比較に float opCmp(...) の形式をサポートします(訳注:戻り値が int ではなく float でも良くなるということです)

ライブラリ変更点

変更点

  • std.algorithm.iteration.permutationsstatic assert メッセージが改善されました。
  • std.system.instructionSetArchitecturestd.system.ISA が追加されました。

改善点

  • Bugzilla 23881: std.system がシステムアーキテクチャに関する機能を持っていない
  • Bugzilla 23922: std.socket の説明リンクを修正

DUB 変更点

  • CLIフラグとして --d-versions が利用可能になりました。

注目トピック

言語・コンパイラ変更点

alias this に代入スタイルの構文が許可されるようになりました。

alias this での宣言が、他のalias宣言と同様の new = old; 形式で書けるようになりました。

struct S
{
    int n;
    alias this = n;
    // 以下と同等:
    //alias n this;
}

元々の構文は alias a b;b が新しく a のように使える、というものでした。
alias b = a; のほうが他の選言や代入の構文と同じなので読みやすい、ということかと思います。
もう全面的にこれで良いのではないかと思うので、ぜひ更新してこれらの機能を使えるようにしていきましょう。

事前定義されたバージョン識別子 VisionOS が追加されました。

これはAppleがVR/ARデバイスであるVision Proのために開発した新しいオペレーティングシステムです。
宣伝するわけではありませんが、物をつかむ、移動させるなどの操作が直観的に行えるとのこと。

XcodeやUnityでの開発が想定されているようですが、D言語でも開発されることが想定されているということでしょう。すごいですね。(語彙が不足)

ランタイムの変更点

druntime に Linux input ヘッダの翻訳が追加されました。

これらのヘッダは、Linux Input SubsystemのユーザースペースAPIにアクセスを提供します。
このAPIは、キーボード、タッチスクリーン、ゲームコントローラーなどからの入力を読み取るためや、入力デバイスをエミュレートするために使用されます。

これらは現在 core.sys.linux を通してインポートすることができます:

import core.sys.linux.input; // linux/input.h
import core.sys.linux.input_event_codes; // linux/input-event-codes.h
import core.sys.linux.uinput; // linux/uinput.h

ガベージコレクタに Valgrind memcheck ツールの統合が追加されました。

今回の目玉、Valgrind memcheck連携です。

Valgrindは、主にLinux向けのメモリ管理とスレッドエラーを検出するためのツール集です。
中でも memcheck は広く利用されているツールで、メモリリークや未初期化メモリへのアクセス、無効なメモリへのアクセスなどの問題を検出できます。
Windowsユーザーだと直接使用する機会は無いかもしれませんが、Linux環境や仮想環境上で開発・テストする場合には非常に有用です。
コンテナ類の運用でお世話になることがあるかもしれません。

今回は、ガベージコレクタをValgrindの memcheck ツールと統合するコンパイル時オプションとして -debug=VALGRIND が追加されました。
これが有効になると、GCは、どのメモリアクセス操作が有効で、どれが無効であるかをValgrindに通知します。

この機能によって、安全なメモリ管理(GC)と安全でないメモリ管理(手動)が混合するプログラムのメモリエラーを検知できるようになります。

例:

program.d
import core.memory;

void main()
{
    auto arr = new int[3];
    GC.free(arr.ptr);
    arr[1] = 42; // use after free (解放したメモリを再使用しており問題)
}

この機能を使うためには、一部DMDのソースコードを取得し、ガベージコレクタとライフタイムの実装をプログラムのコンパイルに含め、-debug=VALGRIND のオプションを付けてコンパイルします。(ちょっと手間で試せていません)

git clone -b v2.105.0 --depth=1 https://github.com/dlang/dmd
dmd -g -debug=VALGRIND program.d -Idmd/druntime/src dmd/druntime/src/{core/internal/gc/impl/conservative/gc,rt/lifetime,etc/valgrind/valgrind}.d
valgrind --tool=memcheck ./program

このオプションは、MEMSTOMPSENTINEL などの他のGCデバッグビルドオプションと互換性があるそうです。

LinuxでValgrindがすでに入っている環境なら、dubのユーザーは以下のコマンドで実際の動作を見ることができます。

git clone -b v2.105.0 --depth=1 https://github.com/dlang/dmd
cat >> dub.sdl <<EOF
debugVersions "VALGRIND"
sourceFiles "dmd/druntime/src/core/internal/gc/impl/conservative/gc.d"
sourceFiles "dmd/druntime/src/rt/lifetime.d"
sourceFiles "dmd/druntime/src/etc/valgrind/valgrind.d"
importPaths "dmd/druntime/src"
EOF
dub build
valgrind --tool=memcheck ./program

Valgrind使いの皆様、D言語でもバッチリ使えるということなので是非試してみてはいかがでしょうか?

ライブラリ変更点

std.algorithm.iteration.permutationsstatic assert メッセージが改善されました。

過去にも行われたエラーメッセージの改善の一種です。

これまで、permutations は、渡された型が使用可能かどうかを確認するためにテンプレート制約を使用していました。

この場合、permutations を使っているテンプレート制約に違反する型を渡そうとすると、テンプレート制約を満たしていない、という意味のメッセージが出ます。しかしこれは、なぜ使用できないのか、を把握する面で非常に面倒でした。

元々使われていたテンプレート制約は記述が容易で書く側には良いのですが、オーバーロード解決と相性が悪い側面があります。
しかし permutations ではオーバーロード解決が必要ないので、テンプレート制約で書く必要はなく、表現力豊かなエラーメッセージが出せる static assert を用いてチェックされるようになった、というのがこの改善です。

std.system.instructionSetArchitecturestd.system.ISA が追加されました。

対象システムの命令セットアーキテクチャ(Instruction Set Architecture, ISA)を表す新しい列挙型と確認用の関数が追加されました。

ISAというのは、いわゆるx86, x64, ARMなど、CPUの種類のようなあれのことです。

今回追加された ISA という列挙型(enum)には、25種類のアーキテクチャと unknown が用意されています。あまり馴染みのないアーキテクチャも対象となっているので、興味があれば一度確認してみてください。(webassembly といった値もあるので、ISAというか実行環境というか、ちょっと微妙ですが)
https://dlang.org/phobos/std_system.html#.ISA

また追加された instructionSetArchitecture という関数は、対象CPUのISAが実行時にのみ必要とされる場合、例えば以下に示すような人間が読めるメッセージの提供などに使用されることを意図しています。

import std.stdio;
import std.system;

void main()
{
    writeln("Hello ", instructionSetArchitecture, " world!");
}

DUB変更点

CLIフラグとして --d-versions が利用可能になりました。

dub build などのコマンドで --d-versions=Xyz を指定することで、Dソースファイルすべてに version = Xyz; の指定を一律追加できるようになりました。
これはdub.sdl / dub.jsonファイルでのバージョン指定と同様ですが、CLIから直接指定する形となり、ビルドタイプや設定とは独立して指定できます。

これはビルドコマンドで設定できるため、config設定も不要でかなり簡略化されます。
たとえばCIパイプラインのビルドで、以下のようにバージョンを切り替えたりすることが簡単にできます。

dub build --d-versions=V1
dub build --d-versions=V2

他にも非推奨機能を有効にするであるとか、一時的に試したいあれこれ、configを作るほどではない開発者なりのあれこれを実現するために、切り替えの手間が大きくs苦言できる便利な機能だと思います。

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

今回は、非推奨が2件、廃止が2件で計4件の機能が非推奨および廃止となります。

余り影響のないものが多いですが、一部わかりづらいものもありますので一つ一つ解説していきます。

また今後の予定などは以下のページにまとまっていますので、こちらも参考としてみてください。

非推奨

  • catch 節は、const または mutable な例外のみを取る必要があります。
  • 関数は enum ストレージクラスの指定ができなくなりました。

削除/エラー

  • extern(C) 関数をオーバーロードすることはエラーになりました。
  • public メソッドでオーバーロードされた private メソッドへのアクセスは非推奨フェーズが終了しました。

非推奨 : catch 節は、const または mutable な例外のみを取る必要があります。

バージョン 2.104 (前回)で、修飾子(const, immutable, など)がついた例外型を throw することは非推奨となりました。

これは同時に immutableinoutshared として例外を catch すること も安全ではないという背景があるためです。
(例外が他の参照を通じてまだアクセス可能である可能性があるなど)

今回から、これらの修飾子で例外を catch する部分が非推奨となります。

テストコード
auto e = new Exception("first");
try {
    throw e;
} catch(immutable Exception ie) { // これは今後エラーとなります。
    e.msg = "second"; // 元の例外を書き換える
    assert(ie.msg == "first"); // これは失敗します。
}
エラーメッセージ
.\deprecate_catch.d(8): Deprecation: can only catch mutable or const qualified types, not `immutable(Exception)`

エラーを見かけたら、原則として型の修飾を外す必要があるかと思います。
また、今は非推奨の警告ですが、エラーになることを見据えて積極的に外す取り組みを行っていただくと良いと思います。
特に例外オブジェクトを受け取って処理する共通関数がある場合、たとえば引数が const であれば catch の部分は修飾不要であり、敷居は高くないと考えられます。
状況に合わせて対応していただければと思います。

削除/エラー : 関数は enum ストレージクラスの指定ができなくなりました。

以前は、関数宣言に enum を用いることが可能でしたが、それが特に副作用がなく、戻り値が存在しない場合には auto ストレージクラスと同等であったため、この書き方は非推奨となりました。
この文法は、enum をマニフェスト定数(列挙型定数)として扱う場合と混同される可能性があるため、今後はエラーとされます。

enum void f1() { }  // エラー
enum f2() { }       // エラー
エラーメッセージ
.\error_enum_func.d(4): Error: function cannot have enum storage class
.\error_enum_func.d(5): Error: function cannot have enum storage class

関数でこれらのエラーが出た場合は enum を取り除き、必要な場合は auto を使用してください。

修正後
void f1() { }
auto f2() { }

正直 auto で戻り値なしも推論してくれるので、大体の用途はこれ1つでカバーできると思います。ただしコード補完などの性能が若干落ちる恐れがあるので注意は必要です。

削除/エラー : extern(C) 関数をオーバーロードすることはエラーになりました。

バージョン 2.095.0 以降で、モジュール内で同じ関数を複数回定義することは許可されていません。これはリンク時にシンボルの衝突が起きるからです。

引数の型が異なる関数のオーバーロードはもちろん許可されており、D言語が引数の型を含むシンボル名をマングリング(変更)するために動作します。
ただし、いくつかの外部リンク(例: extern(C), extern(Windows))はこれを行わないため、それらを使ったうえでオーバーロードするとリンク時にシンボルの衝突が起きる可能性があります。
したがって、このような行為は 2.095 のリリースで非推奨とされていました。

この非推奨は今回エラーに変更されました。
修正方法としては、関数に D または C++ のリンケージを与えるか、オーバーロードごとに独自の関数名を使用してください。

エラーの例:extern(C) でオーバーロード

extern(C) float square(float x) { return x * x; }
extern(C) double square(double x) { return x * x; }
エラーメッセージ(CでもWindowsでも起きる)
.\error_extern.d(2): Error: function `error_extern.square` cannot overload `extern(C)` function at .\error_extern.d(1)
.\error_extern.d(2): Error: function `error_extern.square` cannot overload `extern(Windows)` function at .\error_extern.d(1)

修正策1:関数ごとに名前を変える

extern(C) float squaref(float x) { return x * x; }
extern(C) double squared(double x) { return x * x; }

修正策2:リンケージを外し、オーバーロードが使える extern(D) 相当とする

float square(float x) { return x * x; }
double square(double x) { return x * x; }

特に、C言語とのインターフェースが多いプロジェクトでは、思わずこのようなコードが書かれているケースがあるかもしれません。
しかしC言語側から見ると、ある1つの定義が定まらないとリンクできないため、これまでも実害はなかったものと思われます。(これまでも警告は出ていたため)

何か異常が起きることの無いように早期に修正を検討いただければと思います。

削除/エラー : public メソッドでオーバーロードされた private メソッドへのアクセスは非推奨フェーズが終了しました。

以前は、private メソッドが public メソッドによってオーバーロードされた場合、その private メソッドを public としてアクセスすることができました。

バージョン 2.094 から始まった非推奨期間を経て、以下のようなコードは今後エラーになります。

例:

struct Foo
{
    private void test(int) { }
    public void test(string) { }
}

Foo().test(3);

この例でいうと、Foo().test(3); は引数の型から private void test(int) メソッドに解決されていましたが、これが不可能になります。

エラーメッセージ
.\error_visibility_overload.d(6): Error: function `error_visibility_overload2.Foo.test` of type `void(int)` is not accessible from module `error_visibility_overload`

アクセス保護属性に関するものですので、これは守るほかありません。
同パッケージ内で処理することを想定しているのであれば、private から package に変換してください。
そうでなければ、元来 public が正しい保護属性だった可能性もあります。

エラーを見かけたらアクセス範囲に注意しつつ、適切な対応を検討いただければと思います。

まとめ

Valgrindの連携を中心に、alias this--d-version など、利便性を改善する目的の機能強化がいくつか見られました。
これに加えてVisionOSなどの対応も含まれており、将来への機能強化の意気込みが垣間見えるリリースだったと思います。

また、2023/08/29からD言語の国際カンファレンスである DConf2023 がロンドン(オフライン)で行われます。
コア開発者の方も多くが登壇者であるので、大変な中でのリリースだったと思いますが、かなり苦労されたことと思います。

予定通り無事リリースされて次はDConfということで、こちら申し込み不要でオンライン視聴ができます。ぜひ視聴ご検討ください。

個人的には、何十年とコードを書いてきた作者であるWalter Bright氏による「Crafting Self-Evident Code with D」(Dを使って自明なコードを作る)というキーノートが非常に興味深いと思います。
全体スケジュールは以下リンクです。

さて、次回は順調にいけば10月、次のリリースでどのような話題が出てくるのか、期待して待ちたいと思います!

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4