D言語

【D言語】ETIがRejectされてた

DIP1044、否決

名前付きenum型の識別子を省略しても、それがどの型であるか自動的に推論してくれる ETI (Enum Type Inference) という言語機能が提案されていた。

しかし、フォーラムを見る限り、4月25日に否決されていたらしい。

https://forum.dlang.org/post/fdxkixkcgzrxveayybel@forum.dlang.org

ちなみに、提案の本文はこちら。DIP1044

ETIって?

例えばこんなenumの定義があったとして…

enum Color
{
    red,
    green,
    blue,
}

通常はこのように参照するのだが…

Color c = Color.green;

ETIにより、$を使用することで識別子を省略して参照できるようになる。

Color c = $green;

長い名前のenumをパラメータに持つ関数を呼び出すときなどに、簡潔な記述ができるというのが売りだった。

enum MySuperLongNameOption
{
    option1,
    option2,
    option3,
}

enum MySuperLongNameFlag
{
    flag1 = 0b0001,
    flag2 = 0b0010,
    flag3 = 0b0100,
}

void func(MySuperLongNameOption option, MySuperLongNameFlag flags);

// ETIなし
func(MySuperLongNameOption.option1, MySuperLongNameFlag.flag1 | MySuperLongNameFlag.flag2);

// ETIあり
func($option1, $flag1 | $flag2);

費用対効果

否決された理由だが、やはり費用対効果がネックとなった。

「実装コストに対して得られる恩恵ってそんなにないよね?」というのが公式の総意らしい。

コンテキストに合致する型を要素の識別子だけで推論するのは、実装面でも実行面でも大変なコストがかかる。

関数やテンプレートのオーバーロード解決にも更なる複雑性を持ち込むことになるだろう。

そこまでして得られるものが何かというと、識別子をタイピングする手間が省けることだけ。

ETIほど強力ではないにせよ、識別子を省略できる代替機能は一応存在しているわけだし、何より、優先順位の高い課題がほかにも山積しているD言語の現状を鑑みると、やはり採用には二の足を踏んでしまうといったところだろうか。

それでもenumを省略したい

わかる。

代替策としては、以下のようなものが考えられる。

with句を使う

識別子を指定すると、ブロック内でそれを省略してメンバにアクセスできる。enumに限らず、変数などにも使用できる。

(個人的にfinal switchのお供というイメージが強い。)

with (MySuperLongNameOption)
{
    func(option1);
}

final switch (value) with (MySuperLongNameOption)
{
    case option1:
    // ...
}

最近知ったのだが、複数ネストしても機能するらしい。一番内側のものしか効果が無いものと勝手に思い込んでいたよ。これは、形としてはETIで実現したいことに一番近いかも。(もっとも、enum間で被った名前は参照できないが)

enum Color { red, green, blue }

enum Shape { triangle, square, circle }

enum Size { small, medium, large }

with (Color) with (Shape) with (Size)
{
    auto diagram = createDiagram(red, triangle, large);
}

式(Expression)としては使えないのが残念。こういうことができれば、もっといいんだけどなあ…

// エラー!
auto flags = with (MySuperLongNameFlag) flag1 | flag2 | flag3;

aliasを使う

別名を付けて短くする。

alias Opt = MySuperLongNameOption;

auto変数に代入

これも、変数定義で同じものを2回書くよりはマシかな、と。

auto option = MySuperLongNameOption.option1;

withaliasとの合わせ技でハッピーハッキング。

auto option = Opt.option1;

ゲーム制作への影響

筆者はプロジェクト内で大量のenumを使用している。

立ち絵のパーツIDとか、会話メッセージIDとか、ほかにも細かいものを挙げだすと本当にキリがない。

ETIが実装されれば、タイピングは減るし、コードの見た目もスッキリするし、割といいこと尽くめだなあとホクホクしていたので、ちょっと落胆している。

ゆくゆくはenumからすべての型に派生して、ネームスペースとして使用している構造体やクラスを介した自動推論も期待していたが、叶わぬ夢となった。

イメージとしてはこんな感じ。

struct Account
{
    enum Type
    {
        normal,
        administrator,
    }

    // ...
}

void createAccount(Account.Type type);

// ネームスペースとなっているAccount構造体すらも推論される。
createAccount($normal);

もっとも、タイピング量と見た目の問題だけなので、ゲーム制作自体には全く影響はない。

それに、ETIの実装コストが半端じゃないことは外野の筆者にもわかるので、開発側の気持ちも理解できないでもない。

エコシステム(IDEとかデバッガとか)にも重要なタスクが山積しているこの状況で、こんな些細な機能を追加してる場合じゃないでしょ…っていう主張もまったくその通りだ。

今回の件は残念ではあるけど、仕方がないと諦めがつく。