はじめに
2018年3月1日、D言語の公式コンパイラであるdmd 2.079がリリースされました!
今回change logがかなり大規模で、自分でもよくわからない項目が多かったので内容まとめてみました。
なお、すべての機能をちゃんと試したわけではないので、間違っていたらコメントもらえると助かります。
ざっくりまとめ
- 公式ChangeLog
- https://dlang.org/changelog/2.079.0.html
- いろいろと例が増えた印象です。かなり詳細に記載されていて勉強になりました
- 新機能
- ラムダ式の同一性比較ができる
__traits(isSame, lambda1, lambda2)
の追加 - 任意の関数に対する
@disable
の追加。それをテストできる__traits(isDisabled, func)
の追加 -
-i
フラグによる追加のインポート指定機能(include importモード、というらしい) - ランタイムを独自実装に切り替えられる機能の追加
- 新プラットフォームサポートや組み込み用途の人に朗報
- ラムダ式の同一性比較ができる
- 試験的な機能(experimental)
- 以下のdeprecated期間が終了
- コンマ演算子
- OSX向けの
-dylib
フラグ(今後は-shared
を使う)
- 以下が新たにdeprecatedになった
- delete演算子
- 今後はGC任せか、手動でやりたいなら
core.memory.__delete
- 今後はGC任せか、手動でやりたいなら
- 16進文字列リテラル(
x"304A314B"
みたいなの)- 今後は
std.conv
のhexString!"304A314B"
という感じ
- 今後は
- 選択インポートでprivate宣言まで参照できていた動作
- delete演算子
- その他たくさんの修正や改善
- GCの初期化が最初に使われるときまで遅延される(NoGCなアプリが速くなる)
- Windowsの64bitビルドでVisual C++とWindows SDKに依存しなくなった(うれしい)
- etc.
コンパイラ変更点一覧
- 引数のミスマッチ時のエラーメッセージを改善
- コンマ演算子のdeprecated期間が終了
- 関数のデフォルト引数が可変長テンプレート引数の後は許されなくなった
- delete演算子がdeprecatedになった
- OSXの
-dylib
フラグがdeprecated期間終了。今後は-shared
を使う。 -
-dip1008
フラグで実験的に@nogc例外のスローするようになる - 関数に対する@disable属性のマークをコンパイラで適切に検知できるようになった
- Issue 17630の修正:選択インポートでプライベートなシンボルがインポートできていた
- Issue 17899の修正:コンパイル時にデリゲートを初期化できるようにする
- Issue 18053の修正:long/ulongがint64_t/uint64_tとしてマングルするように変更
- Issue 18219の修正:構造体の中でprivate importされた型が変数宣言に使える
- Issue 18361の修正:Ddocの実行可能テキストにおける自動キーワードハイライト機能をopt-outにする
- Win32とOSXをターゲットにした場合のABIを変更
- 16進文字列リテラルがdeprecatedになった
- 追加のインポートを指定するための
-i
フラグを追加 - JSONにフィールドを追加する
-Xi=<name>
フラグを追加 -
__traits(isSame, ...)
でラムダ式が同じか比較できるようになった - Windowsの64bitビルドでVisual C++とWindows SDKに依存しなくなった
- D言語を、ランタイムなし/最小構成/独自ランタイム、で切り替えて使える仕組みを追加
- macOSのデプロイターゲットを10.9に引き上げ
- 選択インポートでプライベートメンバーまでimportしていた動作がdeprecatedになった
-
@safe
属性の中で配列の.ptrが使用できなくなった
ランタイム変更点一覧
-
core.memory.__delete
を追加 - GCの初期化処理を最初に使うときまで遅延するよう変更
標準ライブラリ変更点一覧
-
std.format
にテンプレート引数でフォーマット文字列を渡すと処理が最適化されるようになった -
std.conv.hexString
がimmutableな文字列を返すように変更 - クラスやインターフェースCに対する
Nullable!C.nullify
が.destroyを呼ばなくなる -
std.algorithm.searching.substitute
を追加 -
std.bigint
にdivModを追加 -
std.bigint
にgetDigitを追加 -
std.exception.enforce
で同名テンプレート(eponymous template)の仕組みを使って独自の関数が作れるようになった - 全モジュールをimportする
std.experimental.all
を追加 -
std.experimental.allocator.IAllocator
をstd.experimental.allocator.RCIAllocator
に置き換え -
std.experimental.allocator.ISharedAllocator
をstd.experimental.allocator.RCISharedAllocator
に置き換え -
readText
がBOMをチェックするようになった -
std.parallelism.TaskPool
にfoldを追加 -
std.range
にnullSinkを追加 -
std.range.slice
(いわゆる固定サイズを持った窓関数)を追加 -
std.string.strip
で取り除く文字を指定できるようになった -
isSomeString
とisNarrowString
がenumに対してfalseを返すようになった -
toString
でOutputRangeを指定できるようになった
変更点紹介
全部翻訳するのは大変そうなので、個人的に注目っぽいところだけまとめます。
ChangeLogにサンプルコードや該当Issueへのリンクもあるので、気になったものは確認してみてください。
コンパイラ変更点
新機能:-i
による追加インポートの指定
ChangeLog: https://dlang.org/changelog/2.079.0.html#includeimports
公式の解説でもimportという言葉が多用されるので、ソースに勝手にimport文挿入できるのかと思ったら全然違いました。
ざっくりいうと、dmd main.d hoge/a.d hoge/b.d ...
と書いていたものが、dmd main.d -i=hoge
でよくなる、という機能です。
もっというとdmd main.d -i=.
で良いです。(ファイル指定なしにはできないので、main.dの指定は必要)
rdmdとかdubを使っている人はあまり使うことがないと思いますが、Makefileでやっている人はちょっと記述がスッキリするかもしれません。
またinclusiveパターンとexclusiveパターンというものがあり、追加だけじゃなくて除外もできます。
exclusiveの記法は頭にハイフンをつけて、dmd main.d -i=hoge -i=-hoge.testing
みたいになります。
新機能:ランタイムを独自実装に差し替える機能
ChangeLog: https://dlang.org/changelog/2.079.0.html#minimal_runtime
object.dとかをソースの1つとして用意しておくことで、ランタイムを独自の物に差し替えたりできる機能のようです。
たとえば、新しいプラットフォームのサポートで空のランタイムを使い、少しずつ機能を実装すると動くようになっていく、といった使い方が想定されています。
ほかにも組み込み用途での利用促進にもつなげていきたい、とか、他言語との親和性が上げられる、とか色々書いてありました。今後に期待しましょう!
ChangeLogにいくつか例がありますが、mainの呼び出しに至る部分も全部書けるので、生成されるバイナリがかなり細かくコントロールできるようになる、というのが注目っぽいです。
バイナリサイズの比較なども具体例があるので、組み込み関係の方は一度詳細確認されてみてはいかがでしょうか!
参考までにChangeLogから引っ張ってくると以下のような内容です。
module object;
extern(C) void __d_sys_exit(long arg1)
{
asm
{
mov RAX, 60;
mov RDI, arg1;
syscall;
}
}
extern void main();
private extern(C) void _start()
{
main();
__d_sys_exit(0);
}
module main;
void main() { }
dmd -c -lib main.d object.d -of=main.o
ld main.o -o main
size main
text data bss dec hex filename
56 0 0 56 38 main
56ばいと…?
試験中:-dip1008
フラグによる@nogc中の例外サポート
ChangeLog: https://dlang.org/changelog/2.079.0.html#dip1008
DIP1008として提案され、事前審査中の機能が試験的に実装されたものです。(正式にはPost-Preliminary Reviewという段階)
今後正式レビューで採用か否決が判断され、否決されると入らない機能なので今はまだ参考程度に眺めておくのが良いと思います。
内容をざっくり言うと「nogc中でも例外が使いたい。throw new Exception("...")したい。」というものです。(正直書いてる最中もまったく意味が分からない)
DIP1008の詳細はこちら: https://github.com/dlang/DIPs/blob/master/DIPs/DIP1008.md
こういった提案は事前審査の前にDraftという下書き提案フェーズがあるのですが、そこは通っているので何かわからないけど大義があるんだと思います。
で、本来メモリが確保されない前提の領域でメモリ確保するっていう話なので、色々な課題が残っています。
興味がある方は使ってフィードバックしてみると良いかもしれません。
※当然nogcなのでGCが動かないからThrowableにオプショナルで参照カウントを付けようとかいろいろ。Rustで言うライフタイムに近い提案であるDIP1000とも関連しています。先は長そう。
修正:import関連
ChangeLog:
インポート関連は実際のプルリクエストを見ると、あれこれまとめて修正されているようです。
特に選択インポートの部分でdeprecatedになった動作があるので、今後注意が必要です。
※一度deprecatedになると何回かあとのリリースで機能が削除されるので、あまり長い間置いておくと突然エラーになります。早めに対処しましょう。
なお、どれも今までアクセス保護属性の仕様に反してシンボルが使えていた状況だった、という問題のようです。
個人的に悩まされた思い出もありますが、対処は人それぞれになると思われます。
まずはdmdを更新して1回ビルドしてみよう!って感じですね。
標準ライブラリ変更点
std.experimental.all
の追加
ChangeLog: https://dlang.org/changelog/2.079.0.html#std-experimental-all
すべての標準ライブラリをまとめてimportできるstd.experimental.all
というモジュールの追加です。
つまり、
import std.algorithm;
import std.math;
import std.stdio;
import std.range;
void main()
{
10.iota.map!log.sum.writeln;
}
import std.experimental.all;
void main()
{
10.iota.map!log.sum.writeln;
}
ということです。
元々std.experimental.sctipting
モジュールとして提案されていたこともあり、D言語をスクリプトのように気軽に使えるようにしようぜって意図があるようです。
今後はWandboxでとりあえずこれ書いとけ、みたいな使い方になるかもしれません。
ちなみにフォーラムで提案されたときは「将来的にimport std;
にしよう」などと言われていました。既存のpackage.dファイルの仕組みを考えるとそうだよね、って感じです。
(しかし何か既視感と嫌悪感があるような…)
まとめ
前回のdmd2.078リリースが2018/01/01でした。
その後3度のマイナーリリースをしながら、(それなりに準備はあったでしょうが)丸2ヶ月でこれだけのアップデートをやったということです。開発陣すごい。
内容としては、便利に使える機能がいろいろ増えたのと、deprecated周りが多く大変健全になった印象ですね。
試験中の機能も追加されていますし、まだまだこれからだ!