KOTET'S PERSONAL BLOG

#dlang Lazyな新しいimportについての議論

Created: , Last modified:
#dlang #tech

これは1年以上前の記事です

ここに書かれている情報、見解は現在のものとは異なっている場合があります。

最近は英語のD言語情報を読めるようになってきて楽しい。 特にGoogle翻訳の改善により、自分の貧弱な英語力でも大半はスラスラとストレスのない速度で読めるようになった。
そういうわけで読んだものを自分の中で解釈し、自分の言葉でゆるく日本語にした記事を書いている。 技術関係だから記事でcontributionを伸ばしても何も後ろめたくないのがいいところだ。

というわけで今回はこちらを読んだ。一部コードをこちらから引用している。

A New Import Idiom` - D Programming Language Discussion Forum

A New Import Idiom – The D Blog

はじめに

現在importは2つの範囲でできる。 module-level importとlocal importである。

// A module-level import
import std.datetime;
  
void fun(SysTime time)
{
  import std.stdio; // A local import
  ...
}

しかしたとえば関数funの引数timeに使われている型SysTimeはmodule-level importされていないといけない。 ちなみにスコープ文を使って下のようなことができるんじゃないかと思ってやってみたがやはりできなかった。

{
    import std.datetime;
    void fun(SysTime time)
    {
        import std.stdio;
        writeln("hello");
    }
}
source/app.d(1,1): Error: declaration expected, not '{'
source/app.d(8,1): Error: unrecognized declaration

そこで 言語へのInline importsの導入が提案された 。 今回読んだものはInline importを今までのものから新しい構文を追加せずにできる形を見つけたという話である。

A New Import Idiom

つまりこういうことである。

template from(string moduleName)
{
  mixin("import from = " ~ moduleName ~ ";");
}

void fun(from!"std.datetime".SysTime time)
{
  import std.stdio;
  ...
}

要素を一つ一つ解説する。

1 !オペレータ

!オペレータでテンプレートをインスタンス化するとき、引数がひとつだけならカッコを省略できる。 つまりfrom!"std.datetime"from!("std.datetime")と同じである。 読みやすい。

2 改名import

改名import。 importするモジュールにローカルな名前を与えて、 その名前で修飾したアクセスを強制することができる。

void printSomething(string s) {
    import io = std.stdio;
    io.writeln(s);         // この形でのみアクセスできる
    writeln(s);            // Error
    std.stdio.writeln(s);  // Error
}

3 Eponymous Templates

Eponymous Templates といって、テンプレートの名前と同じ名前のメンバだけがある場合、省略できる。 これによってたとえばテンプレートが

template from()
{
    import kotet = std.datetime;
}

となっている場合 from!().kotet.SysTime と書かなければいけないところが、改名importでkotetというところをテンプレート名と同じfromにすることで from!().SysTime でよくなる。

ここまでのものを組み合わせるとこのようなコードが書ける。

template dt() {
    import dt = std.datetime; 
}
void fun(dt!().SysTime time) {}

更にこれを一般化する。

4 ~オペレータ

~オペレータで文字列を結合できる。

5 文字列mixin

文字列mixinでコンパイル時にコードを生成できる。 この場合は必要なモジュールをfromとして改名importするコードを作る。 たとえばmoduleNamestd.datetimeなら mixin("import from = " ~ moduleName ~ ";");import from = std.datetime; というコードが生成される。 つよい。

すべてを組み合わせると前述の

template from(string moduleName)
{
  mixin("import from = " ~ moduleName ~ ";");
}

こちらのコードができる。 インスタンス化すると、モジュールの中のシンボルがfromの修飾付きでテンプレートのインスタンスのスコープ内にロードされる。

話し合い

これを使うことでバイナリサイズが元の41%に減少し、コンパイル時間は30%にまで早くなったと 書かれているが 、それはどうやら 勘違いだったらしい

これを標準ライブラリに追加することについては反対する人がいる。 おもな理由としては

PhobosをC++ STLのような恐ろしいシロモノにするのはやめよう

それが引き起こす混乱に見合ったメリットがあるとは思えない

と言った感じである。 一方

DのテンプレートはC++のそれよりはるかに読みやすく直感的だと信じている

という反論がある。