はじめに
D言語の公式コンパイラである dmd が更新され、最新バージョンである 2.091.0
が 2020/03/08 にリリースされました。(ChangeLogの日付によります)
今回はWindows関連とC++連携の強化が多く行われており、ボリュームも結構あるので目立つトピックをメインにまとめたいと思います。
より細かい内容は下記リンクからChangeLogをご覧ください。
- ChangeLog
また、前回1月ののリリースまとめは以下になります。
- D言語の更新まとめ 2020年1月版(dmd 2.090.0)
変更点目次
コンパイラ変更点
- クラスアロケーター/デアロケーターが削除されました。
- GNUエラースタイルのレポートがサポートされました。
- 試験的に
extern(C|C++)
からC++ヘッダーを生成する機能が追加されました。
改善点
- Bugzilla 20569: [DIP1000]
scope
修飾された構造体のフィールドが参照でなければアドレスを取得できるようになります。
ランタイム変更点
- いくつかの環境に対して
pthread_attr_destroy
が追加されました。 -
core.sys.windows.security
の定義が展開、拡充されました。 -
core.stdcpp.memory.unique_ptr
が追加されました。 -
TFD_TIMER_CANCEL_ON_SET
が追加されました。
改善点
- Bugzilla 20146:
std.bigint.BigInt
から組み込みの浮動小数点数へのキャストを許可します。 - Bugzilla 20480:
std.getopt
がDIP 1000
で利用できるようにします。 - Bugzilla 20548:
RandomCover
で1ワードに収まらないとき、bool[]
の代わりにビットベクトルを使うようにします。 - Bugzilla 20566:
std.sformat
では浮動小数点数の出力時にメモリ割り当てを避けるべきです。-
std.format
の間違い?
-
ライブラリ変更点
-
std.bigint
が@safe
になりました。 -
std.math
にてapproxEqual
がisClose
に置き換えられました。 - 非推奨だった
std.format.Mangle
が削除されました。 - 非推奨だった
std.stdio
の構造体、ByLine
,ByChunk
,ByRecord
が削除されました。 - 非推奨だった
std.string
の関数がいくつか削除されました。 -
std.algorithm.sorting.schwartzSort
が2引数関数による変換がサポートされました、 -
std.functional
にcurry
が追加されました。
改善点
- Bugzilla 19218:
object.destroy
はクラスの静的配列をチェックすべきです。 - Bugzilla 20550: GCで使うtreapのため固定のシードを使うようにします。
- Bugzilla 20567: 単純なプログラムにおいて、GCの並列マーキングのためにスレッドを開始するべきではありません。
- Bugzilla 20577: Windows UACに関するシンボルを追加します。
- 主に
sdkddkver.h
に相当する内容がcore.sys.windows.sdkddkver
に追加された
- 主に
インストーラー変更点
- インストールスクリプトがWindowsで動作するようになりました。
- リリースされた
dmd.exe
はLDC
でビルドされ、コンパイル時間が30%から40%改善されます。 -
dmd.exe
とlld-link.exe
の64-bit版のビルドがbin64
フォルダに追加されました。 - 付属のWindowsライブラリと定義が
MinGW 5.0.2
からMinGW 7.0.0
に変更されました。(ワイド文字列のmainエントリポイントの追加と共に)- 翻訳が怪しいです
- Windowsバイナリに付属しているLLDリンカは、9.0.0(例外がWin32上で動作するようにするパッチを含む)にアップグレードされました。
- MinGWインポートライブラリにリンクされているVCランタイムが
msvcr120.dll
にアップグレードされました(最新バージョンは、単純なコピーを可能にし、汎用Cランタイムに依存しません)。再配布可能なDLLは、追加のインストーラを実行しなくてもすぐに使用できるように、それぞれのbinフォルダに追加されています。 -
curl
のライブラリとDLLは7.68
に更新されました。 - 古い
windbg.exe
が削除されました。 - インストーラはVS2019のインストールを検知するようになりました。VCのインストールが見つからない場合、提案されるダウンロードはVS2017ではなくVS2019になります。
※ChangeLog上「the couple of updates」としてまとめられていたものもこちらで一覧にしました
DUB変更点
- 環境変数として
SOURCE_FILES
が追加されました。 - zshの補完が追加されました。
注目トピック
言語・コンパイラ変更点
強化:GNUのエラースタイルが利用可能になった
コンパイル結果に表示されるエラー報告で、GNUのエラースタイルが利用可能になりました。
これによって既存のIDEと互換性が高まるなどが期待されています。
具体的な形式としては、 filename:line[:column]: message
となり、使うには -verror-style=gnu
と指定します。
(あんまり変わってないような…?)
試験的:C/C++向けのヘッダーが生成可能になった
今回のリリースの目玉となっている強化です。
extern(C)
や extern(C++)
というリンケージが付いている宣言に対し、-HC
や -HCf=<file>
、-HCd=<directory>
というフラグを付けるとC++向けのヘッダーが生成できるようになりました。
元々D言語自体がC++からの移行を考えて作られていることもあり、既存システムをDで置き換えていく、という目標に対して重要なマイルストーンの1つとなっています。
既存システムの書き換えとして、大きく以下2つの方向性があるわけですが、今回前者が強化された格好になります。
- C++で書かれたシステムに対し、部品の一部をDで書き直す(表面がC++、中身はD)
- C++で書かれたシステムから部品を抜き出し、Dで書かれたシステムから利用する(表面がD、中身はC++)
どんなものが変換されヘッダーが生成されるのか、ChangeLogを抜粋してくると以下のようになっています。
module a;
extern(C) int foo(int a) { ... }
extern(C++) void bar() { ... }
void ignored() { ... }
module b;
extern (C++) struct S
{
string name;
this (string name) { ... }
bool bar() { ... }
}
module c;
import a, b;
extern (C++) class C
{
S[] s;
this () {}
bool bar() { ...}
}
これを dmd -c -o- -HC a.d b.d c.d
でコンパイルすると下記が生成されます。
#pragma once
// Automatically generated by dmd -HC
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#define _d_void void
#define _d_bool bool
#define _d_byte signed char
#define _d_ubyte unsigned char
#define _d_short short
#define _d_ushort unsigned short
#define _d_int int
#define _d_uint unsigned
#define _d_long long long
#define _d_ulong unsigned long long
#define _d_float float
#define _d_double double
#define _d_real long double
#define _d_char char
#define _d_wchar wchar_t
#define _d_dchar unsigned
typedef _d_long d_int64;
#define _d_null NULL
// Parsing module a
// Parsing module b
// Parsing module c
struct S;
extern "C" _d_int foo(_d_int a);
extern _d_void bar();
// ignoring function a.ignored because of linkage
struct S
{
DArray< _d_char > name;
S(DArray< _d_char > name);
_d_bool bar();
S() : name() {}
};
class C
{
public:
DArray< S > s;
C();
virtual _d_bool bar();
};
#define
が多いのはそういうものとして、結構無難に生成されている感じでしょうか?(DArrayの定義はどこ…?)
#pragma once
を使うあたり今風のような気もしますが、機械的に生成するなら普通のインクルードガードでも良いような気がしつつ、将来的にフラグで切り替えられるようになるかもしれません。
試験的な機能なので今後に期待です。
ランタイム変更点
強化: core.stdcpp.memory.unique_ptr
が追加された
されました。
以前から継続しているC++連携強化施策の1つです。
C++のライブラリでも unique_ptr
はよく出てくるので、これでまた1つ壁を乗り越えた、という感じですね。
std::vector
や std::string
は以前対応されたので、これで移植できるライブラリがかなり増えそうです。
個人的に「内部実装を考えると移植厳しすぎない?」と思っていたので、無事に実現されて一安心です。
compressed_pair
と呼ばれるフィールドを持たない構造体に対する最適化イディオムまでサポートされており、こういうのもDでちゃんと対応できるんだな、というのがとても勉強になります。
ライブラリ変更点
強化: std.bigint
が @safe
に対応した
なぜ今まで対応してなかったの?というと、実装優先だったことと内部的にインラインアセンブラを使っている箇所が多かったからです。(インラインアセンブラは無条件にsafeにできない)
大半は @safe
の追加なのですが、 何か所か @trusted
を使い、即時関数の呼び出しを用いる変更が入っています。
r.data = cast(immutable) subInt(x.data, y);
r.data = (() @trusted => cast(immutable) subInt(x.data, y))();
@trusted
は「機械的には保証されないが信用されたコード」という意味で、こうすると動作は変えずに多くの式を @safe
の中で呼び出すことができます。
ライブラリの改善で @safe
を付けるという話は結構あるので、こういったイディオムとして覚えておくといつか役立つかもしれません。
変更:std.math
の中で approxEqual
を isClose
に置き換え
浮動小数点数を適切に比較するため、新しく isClose
テンプレート関数が追加されました。
浮動小数点数の比較には元々 approxEqual
テンプレート関数がありましたが、より良い初期値と引数対称性を持っていることが追加理由となっているようです。
今後のリリースで approxEqual
は非推奨(deprecated)となり、最終的には廃止される予定となっていますが、利用側としては特に書き換えの必要はありません。
(deprecatedにする必要もない気がしますが…)
また、approxEqual(a, b)
は isClose(a, b, 1e-2, 1e-2)
でほぼ置き換えが可能とのことですが、誤差指定がない場合は isClose(a, b)
での書き換えが推奨されています。
(多分 isClose(a, b, 1e-2, 1e-5)
の間違いです)
approxEqual
と isClose
の違い
approxEqual
と isClose
は共に、相対誤差が一定以下 or 絶対誤差が一定以下、という条件をチェックします。
相対誤差と絶対誤差は第3引数と第4引数でそれぞれ指定します。
違いの1点目は絶対誤差の初期値で、 isClose
の初期値は絶対誤差が 0.0
となります。
これによって表面的には相対誤差の結果のみを考慮するようになります。
引数の対称性については、相対誤差の基準値を第2引数から算出しているという意味のようで、詳細は以下の記事が参考になります。
- 浮動小数点数の比較で許容する相対誤差と絶対誤差
isClose
は第1引数から算出した相対誤差も考慮されるため、以下のように isClose
だけOKになるケースが出てくるようです。
real a = 100.1;
real b = 100;
real maxRelDiff = 0.0009995; // 相対誤差の上限
writeln(approxEqual(a, b, maxRelDiff)); // false
writeln(isClose(a, b, maxRelDiff)); // true
とまぁ精度が重要であれば、相対誤差と絶対誤差を両方指定して使ったり、保証される値域を確認してみたりすると良いのではないかと思われます。
名前について
余談ですが、2020年3月10日現在、Google翻訳ほかいくつかのサービスでは概ね X is close to Y
で「XはYに近い」、X approx equal to Y
のほうを「XはYにほぼ等しい」と訳してくれます。
isClose
という名前自体はPythonから取っているようですが、個人的には数学的な意味で approxEqual
のほうが適切だったのかなと思われ、今後 isClose
が推奨されるのはちょっと複雑な気持ちです。
強化:std.algorithm.sorting
の schwartzSort
で2引数の変換関数をサポート
これだけ見てもなんのことやらという感じですが、schwartzSort
自体は「配列の各要素に対して1度だけ計算を施し、その結果をもってソートする」という関数です。
この計算をする関数は、元々 a => heavyFunc(a)
といった感じで何か重い処理をする1引数関数が想定されていました。
今回これに「インデックスを第2引数に受け取る2引数関数」が指定できるようになります。
試しに使うと以下の通りで、インデックスは初期状態の位置が指定されます。
これによって、配列の位置によって優先度をつけたり、一定範囲のみ別の計算結果を利用したり、といった切り分けが可能になります。
import std;
struct S {
int n;
}
void main() {
S[] ss;
foreach (i; 0 .. 10)
{
ss ~= S(10 - i);
}
// 要素をa、インデックスをiで受け取る
schwartzSort!((a, i) {
writeln(i, " : ", a);
return a.n;
}, "a < b")(ss);
}
0 : S(10)
1 : S(9)
2 : S(8)
3 : S(7)
4 : S(6)
5 : S(5)
6 : S(4)
7 : S(3)
8 : S(2)
9 : S(1)
強化:std.functional
に curry
を追加
関数をカリー化する curry
テンプレート関数が追加されました。
関数型プログラミングの文脈ではよく出てくるカリー化ですが、メタプログラミングの練習で似たようなライブラリがたくさんあると思います。
今回標準ライブラリに追加されたので簡単に使えるようになりました。きっと良いことだと思われます多分。
と、関数呼び出しができるものであれば構造体でも対応しており、以下のような感じで使えます。
こういう関数が増えて楽しく開発できるようになると良いですね。
import std.functional : curry;
struct S
{
int w;
int opCall(int x, int y, int z)
{
return w + x + y + z;
}
}
S s;
s.w = 5;
auto cs = curry(s);
auto cs1 = cs(1);
auto cs2 = cs(2);
assert(cs1(2)(3) == s(1, 2, 3));
assert(cs1(2)(3) == (1 + 2 + 3 + 5));
assert(cs2(2)(3) == s(2, 2, 3));
インストーラー変更点
強化:インストールスクリプトがWindows上で動作するようになった
公式のインストールスクリプト( https://dlang.org/install.sh )が CygWin
や Msys2
などのPOSIX-Likeな環境から利用できるようになった、という強化です。
Windowsではあまり使われなかったインストールスクリプトですが、これで大体の環境から統一された方法でDMDやLDC、dubなどがインストールできるようになりました。
ちなみにWindows 10なら、PowerShellから Get-PackageProvider Chocolatey
および Install-Package dmd
とすればほぼ自動でインストールできるので、バージョン切り替えなどを使わなければこれで十分なのでは?という気もします。
速度改善
DMDは元々DMD自身でコンパイルして配布(セルフホスト)されていますが、今回のリリースではLDCを使ったバイナリになるようです。
元々速かったコンパイルが更に30%から40%改善するだろうとのことで、速度に関してはかなり期待できそうです。
付属のライブラリ更新
リンカのLLD
や VCランタイム、curl
といった付属品の多くがバージョンアップされました。
今回が1つの節目となるかと思われますので、何かアプリを作っている方は1度動作確認をしておくほうが良いかと思われます。
使う側としては、まとめて更新されると検証が少なくて良いので楽ですね。
非推奨または廃止される機能
廃止された機能
今回は追加の非推奨なし、削除された機能が4件です。
- クラスアロケーターが削除されました。
- 非推奨だった
std.format.Mangle
が削除されました。-
std.demangle.demangle
で代用できます。
-
- 非推奨だった
std.stdio
の構造体、ByLine
,ByChunk
,ByRecord
が削除されました。- それぞれ
byLine
,byChunk
,byRecord
という関数で代用できます。
- それぞれ
- 非推奨だった
std.string
の関数がいくつか削除されました。-
inPattern
,countchars
,removechars
,squeeze
,munch
が削除されました。- コードは完全に除去され、今後はこういった関数をまとめておくUndeaDというパッケージに置かれます
- https://code.dlang.org/packages/undead
-
まとめ
追加の非推奨は無し、言語機能の強化は限定的、とかなり落ち着いている状況ですが、Windows周りを含め周辺強化が目立ったリリースではないかと思います。
特にWindows民としてはインストーラーの改善が目立つ部分で、UAC周りのシンボル追加があったことを踏まえると、かなり消費者向けのアプリ作成やそういった開発者層にまで裾野が広がってきたのかなと感じます。
C++連携の強化も含め、以前から考えられていた強化案がかなり具体化してきていますし、今後は所有権関連の強化も予定されています。
次回リリース予定は5月、引き続きの強化に期待したいと思います!