D言語のUFCSが好きだ！

# __D言語の特徴的な機能としてUFCSがある__

他の言語にも同様の機能があるようですが、D言語のそれには使っていて楽しいと思えるいくつかの特徴があり、好んで使うD言語erも多いようです。(私もよく使ってます！)
私がUFCSするときに感じた、利点などをまとめてみました。
[dmd2.068.2にて動作確認]

# __UFCSとは__

__UFCS (Unified Function Call Syntax)__とは、関数呼び出しについてのシンタックスシュガーで、ほとんどの関数について、`func(obj, ...)`を`obj.func(...)`と記述することを許すというシンプルな機能です。
挙動としては、`obj`に`.func(...)`が存在しない場合、`func(obj, ...)`の呼び出しを試みるという感じです。
※逆に、`obj.func(...)`を`func(obj, ...)`と記述することはできません。

```d:D
// これが
writeln("hello,world!");

// こうなる
"hello,world!".writeln;
```

# __何がうれしいのか__

## 疑似的なメンバ関数により、ユーザー定義型をシンプルに記述できてうれしい！

UFCSは、__オブジェクトの疑似的なメンバ関数のような見た目__なので

```d:D
import std.stdio;

/**
 * 大量のヘルパー的なメンバ関数で、クラスの構造がわかりづらくなる
 * また、クラスの定義とヘルパー的なメンバ関数の間に、依存関係ができてしまう
 * かといってヘルパー関数としてクラス外に出すと、関数の呼び出しが使いづらい
 */
class C1
{
    // 型定義がごちゃごちゃ
    private int n_;
    this()          { }
    void helper1()  { "あんなこと".writeln; }
    void helper2()  { "こんなこと".writeln; }
    void set(int n) { n_ = n; }
    void helper3()  { "そんなこと".writeln; }
    int  get()      { return n_; }
    void helper4()  { "どんなこと".writeln; }
}
// C1型に依存
void helper5(C1 x)  { "わいわい".writeln; }
void helper6(C1 x)  { "がやがや".writeln; }

/// そこでUFCS!!
class C2
{
    // 型定義はシンプルに
    private int n_;
    this()          { }
    void set(int n) { n_ = n; }
    int  get()      { return n_; }
}
// 依存性は抑えめに
void helper1(T)(T x) if (is(T : C2)) { "あんなこと".writeln; }
void helper2(T)(T x) if (is(T : C2)) { "こんなこと".writeln; }
void helper3(T)(T x) if (is(T : C2)) { "そんなこと".writeln; }
void helper4(T)(T x) if (is(T : C2)) { "どんなこと".writeln; }
void helper5(T)(T x) if (is(T : C2)) { "わいわい".writeln;   }
void helper6(T)(T x) if (is(T : C2)) { "がやがや".writeln;   }

void main()
{
    // 通常
    auto c1 = new C1;
    c1.set(42);
    writeln(c1.get);
    c1.helper1;   // 型定義にこれ必要？
    c1.helper2;   // 　〃
    c1.helper3;   // 　〃
    c1.helper4;   // 　〃
    helper5(c1);  // 仲間外れでつらい
    helper6(c1);  // 　〃

    // UFCS!!
    auto c2 = new C2;
    c2.set(42);
    c2.get.writeln;
    c2.helper1;   // まるでメンバ関数!!
    c2.helper2;   //   〃
    c2.helper3;   //   〃
    c2.helper4;   //   〃
    c2.helper5;   //   〃
    c2.helper6;   //   〃
}
```

型定義の本体はシンプルな内容に留め、かつ疑似的なメンバ関数として同様の処理を提供できます！
(おそらくこれが本来のUFCSの目的？)

## 関数をどんどんつなげて記述できるチェイン記法がうれしい！

UFCSと、__引数のない関数は、関数呼び出しの`()`を省略できる__というD言語の仕様を組み合わせると

```d:D
int hoge(int n) { return n + 2; }
int fuga(int n) { return n * 3; }
int piyo(int n) { return n / 5; }

void main()
{
    // 変数xの値をhogeした後、fugaして、piyoした結果を表示したい
    auto x = 68;

    // 通常の記述
    import std.stdio;
    writeln(piyo(fuga(hoge(x))));

    // ↓
    writeln(piyo(fuga(x.hoge)));
    // ↓
    writeln(piyo(x.hoge.fuga));
    // ↓
    writeln(x.hoge.fuga.piyo);
    // UFCS !!
    x.hoge.fuga.piyo.writeln;
}
```

こんな感じで、UFCSチェインして__気持ちよく__記述できます！
(これがしたくて使っていると思う！)

# __その他の効能__

~~TODO: 適当なコード片をサンプルとして書き足す~~
[2015.10.17サンプル追記]

* ある程度複雑な処理を__ワンライナー__で記述できる！
* __ネストされた`()`が減る__ことで、入力が楽で間違えにくい！
* __視線の方向(左から右)に記述__でき、処理の流れが追いやすい！

元ネタ:「[1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に](http://www.softantenna.com/wp/software/5-programming-problems/)」
参考にしました→「[Java8で「ソフトウェアエンジニアならば1時間以内に解けなければいけない5つの問題」の5問目を解いてみた](http://qiita.com/tag1216/items/25ff0f957340c54ae73c)」

```d:D
import std.range     : iota, array;
import std.conv      : to;
import std.algorithm : map, filter, sum, each;
import std.array     : join, split;
import std.stdio     : writeln;

R combination(R, R sep = [" +", " -", ""])(R elem)
{
    return elem.length < 2
        ? elem
        : sep
            .map!(op => combination(elem[1 .. $])
                  .map!(x => elem[0] ~ op ~ x))
            .join;
}

void main()
{
    iota(1, 10).array
        .to!(string[])
        .combination
        .filter!(a => a.split(" ").to!(int[]).sum == 100)
        .each!(a => a.writeln);
}
```

* 関数設計時の引数順序のゆるい指針: __とりあえずUFCSでつながるように！__

# __はまり所__

* メンバ関数、ネスト関数、ラムダ式はUFCSできない

```d:D
class C
{
    // メンバ関数
    static int sfoo(int n) { return n * 2; }
           int nfoo(int n) { return n * 2; }
}

void main()
{
    // ネスト関数
    static int sbar(int n) { return n * 2; }
           int nbar(int n) { return n * 2; }
    // ラムダ式
    static auto sbaz = (int n) => n * 2;
           auto nbaz = (int n) => n * 2;

    import std.stdio;
    //1.C.sfoo.writeln;        // NG
    //1.(new C).nfoo.writeln;  // NG
    //1.sbar.writeln;          // NG
    //1.nbar.writeln;          // NG
    //1.sbaz.writeln;          // NG
    //1.nbaz.writeln;          // NG
}
```

[2015.10.17追記]
  __→UFCSできない場合、`std.functional`の`pipe`や`compose`でつなげる方法もあるそうです__

* 多段階にはUFCSできない (当たり前)

```d:D
int foo(int a, int b, int c) { return a + b + c; }

void main()
{
    import std.stdio;
    auto a = 1, b = 2, c = 3;
    a.foo(b, c).writeln;    // OK
    //b.a.foo(c).writeln;   // NG
    //c.b.a.foo.writeln;    // NG
}
```