はじめに
D言語の公式コンパイラである dmd が更新され、最新バージョンである 2.089.0
が 2019/11/02 にリリースされました。
今回もほぼ予定通りのスケジュールで、言語的な強化は控えめながらツール周りでいくつか目立った強化が行われました。
また不具合修正の一環で多数の改善が入っているので、これもいくつか拾っておきたいと思います。
より細かい内容は下記リンクからChangeLogや公式ブログの原文をご覧ください。
- ChangeLog : https://dlang.org/changelog/2.089.0.html
また、前回9月ののリリースまとめは以下になります。
- D言語の更新まとめ 2019年9月版(dmd 2.088.0)
変更点目次
コンパイラ変更点
-
foreach
ループで許可されていた変数のshadowingが廃止されました。 - is式が
const
、inout
、shared
の組み合わせに正確に一致するようになりました。 -
template mixin
中のextern(C)
宣言がグローバルスコープで使われたとき、Cのマングルでシンボルを生成します。 - Digital Marsのツールチェインにおけるデフォルトのリンカが
optlink.exe
になります。 - Issue 6952のため、新しく
-Xcc
コンパイラフラグが追加されました。
改善点
- Bugzilla 809: lazyな引数はdelegateに変換できるべきです。
- Bugzilla 1547: デフォルト引数の値は暗黙的なopCallを使うべきです。
- Bugzilla 3004: 不正なpragmaのハンドリングを改善
- Bugzilla 18272:
-gf
のchangelogとドキュメントがない (参照された型について不可解なデバッグ情報が出力される) - Bugzilla 18617: 式がdeprecatedであるか確かめるために
__traits(deprecated, expr)
が必要です。
ランタイム変更点
-
core.atomic
にatomicFetchAdd
とatomicFetchSub
を追加します。 -
wstatus
をpure
と@safe
にします。- 訳注)Posixの
wait(2)
をpure/@safe
にする、という意味のようです
- 訳注)Posixの
改善点
- Bugzilla 8831:
core.atomic
に 異なる戻り値のcompare-and-swap
関数を追加します。 - Bugzilla 13826:
volatileLoad
とvolatileStore
をcore.volatile
へ移動します。 - Bugzilla 15007:
core.atomic
を C++11 に合わせる - Bugzilla 20105:
core.atomic
のcas
関数が不完全 - Bugzilla 20106:
core.atomic
のatomicFence
がMemoryOrder
の指定を受け付けない - Bugzilla 20107:
core.atomic
の Memory order にキーが不足している
訳注)いくつかをまとめて atomicFetchAdd
あたりに還元されており、トピックとしては core.volatile
の追加が大きいです
ライブラリ変更点
-
std.traits.Unconst
を追加
改善点
- Bugzilla 20147:
std.bigint.BigInt
と浮動小数点型の間で比較(==, >, >=, <=, <)が有効になりました。 - Bugzilla 20159:
std.math.scalbn
がCTFE可能となりました。 - Bugzilla 20192:
std.math.isSubnormal
がCTFE可能となりました。 - Bugzilla 20196:
std.math.isNormal
がCTFE可能となりました。 - Bugzilla 20199:
std.math.frexp
がCTFE可能となりました。 - Bugzilla 20200:
std.math.isPowerOf2
が浮動小数点数に対してCTFE可能になりました。 - Bugzilla 20201:
std.math.scalbn
がpure
になりました。 - Bugzilla 20202:
std.math.signbit
がCTFE可能となりました。 - Bugzilla 20203:
std.math.copysign
がCTFE可能となりました。 - Bugzilla 20242:
BitArray
のコンストラクタは入力値を変更しないべきです。
DUB変更点
- LDCにおけるクロスコンパイルのサポートを改善しました。
-
Lint
コマンドを追加しました。 - セマンティックバージョニングにおける "^" の指定を追加しました
注目トピック
言語・コンパイラ変更点
強化: is式の推論改善
is式の推論が少し賢くなりました。
Change Logの抜粋ですが、以前は通らなかった以下の判定が通るようになります。
static assert(is(shared(const int) U == shared U) && is(U == const int));
static assert(is(shared(inout int) U == inout U) && is(U == shared int));
ランタイムにも Unconst
の追加という強化があるので、このあたりの推論と何かつながりがあるのかもしれません。
いずれにしてもメタプログラミングが捗りそうです。
強化: template mixin
中の extern(C)
宣言の変更
Change Logの例から一部抜粋ですが、要するに「WebAssemblyのエントリポイントをよろしく生成するテンプレートを書きたい」という要望に応えるための強化のようです。
// library code
mixin template WasmEntryPoint() {
extern(C) export void _start() {
// boilerplate code
}
}
// application code
mixin WasmEntryPoint;
static assert(_start.mangleof == "_start");
こういった取り組みも行われているということで、今後WebAssembly関連のライブラリ強化も期待できそうですね!
改善: lazy
な引数が delegate
に変換可能になります。
lazy
というのは関数引数の修飾子で、その引数の評価が使われるときまで遅延される、というものです。
たとえばフラグに応じて処理をするか切り替えるとき、「使わないかもしれない値を先に計算して用意しておく」というのはできれば避けたいですよね。
lazy
を使うと以下のように書くことで遅延評価になります。
// lazy引数で遅延評価
void times(int n, lazy string message) {
while (n--)
writeln(message);
}
// 繰り返し回数は実行時ゼロになることを想定
int n = 0;
int days = 10;
string s = "days";
string m = "later";
// formatの部分はlazyになっているので1度も評価されない
n.times(format!"%d %s %s"(10, s, m));
これを lazy
なしに実現しようと考えた場合、 string
ではなく string delegate()
として、以下のようになるでしょうか。
void times(int n, string delegate() message) {
while (n--)
writeln(message());
}
これは lazy
に対して内部的に行われていることとほぼ同じなのですが、表現の分かりやすさから lazy
キーワードが導入されています。
逆に中身を知ってしまうと、「元々 delegate
と変わらないのだから変換できても良いだろう」ということで改善された格好になります。
実際に変換するには以下のようになります。
void test(lazy string t)
{
string delegate() dg = &t; // アドレスを取るイメージで変換できる
string s = dg();
}
ちなみにこれをキャストで変換しようとするとエラーになるので注意してください。
互換性などの問題があるのかもしれませんがちょっと思いつかず、実際に問題になるようなケースをご存知の方がいれば教えてください。
ランタイム変更点
強化: core.atomic
に atomicFetchAdd
と atomicFetchSub
を追加
今回追加されたのはC++に元々ある std::atomic::fetchAdd
等にあたる関数です。
機能としては、既存の atomicOp
をそれぞれ +
または -
演算子で実行してアトミックに置き換え、元の値を返す、というものになります。
(既存の atomicOp
は値を置き換えてその値を返すため、変更前の値は取得できません)
サンプルは以下のようになります。
import core.atomic;
shared x = 10;
auto y = atomicFetchAdd(x, 10);
assert(x == 20);
assert(y == 10);
こちら、前回9月のリリースで cas
のオーバーロードや atomicExchange
の追加がありましたが、今回もその流れで強化があったようです。
こういった関数の追加で使い勝手が良くなって、非同期のプログラムが気楽に書けるようになるのはありがたいですね!
ライブラリ変更点
std.math
におけるCTFE強化
今回複数の関数がCTFEに対応しました。
使う頻度が少ない関数もあるようですが、それなりに数があるのでかなり目を引きます。
ちなみにざっくり機能などまとめると以下の通りで、かなりコアな部分までカバーされた印象です。
-
scalbn
-
scalbn(x, n)
でx * (2 ^^ n)
を求めます。
-
-
isSubnormal
-
isSubnormal(x)
でx
が非正規数かどうかを判定します。
-
-
isNormal
-
isNormal(x)
でx
が通常の数(NaNやinfinity、0または非正規数でない)かどうかを判定します。
-
-
frexp
-
frexp(x, exp)
で浮動小数点を指数部と仮数部に分解します。戻り値が仮数部、exp
が指数部になります。
-
-
isPowerOf2
-
isPowerOf2(x)
でx
が2のべき乗かどうかを判定します。
-
-
signbit
-
signbit(x)
でx
の符号ビットを取得します。負数なら1、正の数なら0になります。
-
-
copysign
-
copysign(a, b)
で、値はa
、符号はb
と同じになる値を求めます。
-
DUB変更点
強化: LDCのクロスコンパイルに対応
LDC 1.18.0でクロスコンパイルに対応したのを受けて、dubのビルドにおける --arch
にLDCの -mtriple
と同じ値が指定できるようになりました!
これでWindowsからLinuxバイナリを出力できたりするほか、WebAssemblyのビルドやAndroid関連のビルドをdubで行えるようになると思われます。(まだ実験不足です)
具体的に -mtriple
に指定できる値は以下を参照してください。
ちなみに主要なプラットフォームの例を挙げると以下のような感じです。
プラットフォーム | mtriple |
---|---|
Linux x86_64 with glibc | x86_64-linux-gnu |
macOS | x86_64-apple-darwin16.7.0 |
Windows x64 | x86_64-windows-msvc |
Android ARMv7-A | armv7a-unknown-linux-androideabi |
32-bit WebAssembly | wasm32-unknown-unknown-webassembly |
強化: lint
コマンドの追加
シンタックスやコメントの有無をチェックできる lint
コマンドが追加されました。
dubプロジェクトのトップで dub lint
とすることで DScanner を使った構文チェックとスタイルチェックを行うことができます。
見つけた警告によってリターンコードが1になったりするので、CIに組み込むことで継続的なチェックが可能です。
また、解析結果をJSONで出力する --report
というフラグもあるため、これを解析すれば何かを活かせるかもしれません。
非推奨または廃止される機能
今回は foreach
における変数宣言の shadowing が廃止されるのみです。
追加で非推奨になる機能はありません!
通常の for
ループではshadowingがエラーになるため、同じ問題で引っかかるケースは稀かと思われます。
また以前からずっと非推奨だったので、警告に気を配っていれば影響を受けることはないと思います。
int n;
foreach (i; 0 .. 100) {
int n = i * 10;
writeln(n);
}
まとめ
修正された不具合もそれなりにありますが、求められた機能の追加を中心にツール周りが整えられた印象のリリースです。
また、「新たに非推奨になった機能等がない」というのは、「Breaking changes」という見出しが毎バージョン踊っていたころと比べて非常に印象的です。
少し前から不評な機能を消すことに終始していたのもあり、今回のリリースが1つの節目なのかと思われます。
というわけでリリースのまとめは以上です。
次は年明け元旦予定のリリースを期待して待ちつつ、今後リリースされるであろう大規模機能強化にも注目したいと思います!
(アドベントカレンダーが近いので、今年話題になったネタはある程度そちらでまとめたいと思います)