【C++ Advent Calendar 2016 22日目】C++ で enable_if を使うコードのベストプラクティス

[追記]

すみませんすみません、修正しました。

[本編]

C++ Advent Calendar 201622日目の記事です。
『ベストプラクティス』と書いていますが、釣りタイトルですです。誰かもっといい書き方教えてください。
最近さっぱり C++ を書いてないのでいろいろと厳しい。
あ、あと最初に書いておくと本記事はあくまでも『enable_if の使い方』に関する記事なので SFINAE 自体にはあまり言及しません。

[enable_if とは]

enable_if は一般的にSFINAE を利用したコンパイル条件分岐で使用するためのメタ関数になります。
SFINAE とは cpprefjp から引用すると

「SFINAE (Substitution Failure Is Not An Errorの略称、スフィネェと読む)」は、テンプレートの置き換えに失敗した際に、即時にコンパイルエラーとはせず、置き換えに失敗した関数をオーバーロード解決の候補から除外するという言語機能である。

たとえば、関数のシグニチャの一部として「typename T::value_type」が書いてあり、型Tがvalue_typeという型を持っていない場合、その関数がオーバーロード解決から除外される。これによって型が任意の機能を持っているかを、コンパイル時に判定できた。

参照:任意の式によるSFINAE - cpprefjp C++日本語リファレンス

とのこと。
例えば、関数テンプレートの呼び出しの際にテンプレート引数の型が『整数型かそうでないか』で呼び出す関数を切り分けたい場合などで SFINAE と enable_if を組み合わせて使用します。
まあ C++ を書いてる人であれば enable_if や SFINAE などは知っていて当然ですよね。
それでは実際に enable_if を使ったコードを書いていきます。

[C++03 時代の enable_if]

まず、C++03 時代の enable_if の利用方法を書いてみましょう。
C++03 ではまだ enable_if は標準ライブラリに入っておらず、Boost を利用します。

#include <boost/core/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

template<typename T>
void
func(T t, typename boost::enable_if<boost::is_integral<T> >::type* = 0){
    std::cout << t << "は整数だよ" << std::endl;
}

void
func(...){
    std::cout << "引数は整数じゃないよ" << std::endl;
}

func(10);       // 10は整数だよ
func('c');      // cは整数だよ
func(3.14f);    // 引数は整数じゃないよ

http://melpon.org/wandbox/permlink/w3oZ2lSl1aS8bbTa

C++03 時代では割とオーソドックな書き方になるかと思います。
C++03 では『関数のデフォルト引数として enable_if::type を定義してる』のが肝になります。
また『テンプレート型の条件』には is_integral というメタ関数を使用しています。
このメタ関数は『整数型であれば is_integral::valuetrue を返し、そうでないなら false』という関数になります。
このメタ関数と enable_if を組み合わせることで関数呼び出しの条件分岐を行っています。
ちなみに boost::enable_if の場合は内部で ::value が呼び出されるので、呼び出し側では ::value をつける必要はないので『生の型』をそのまま enable_if へと渡します。

[C++11 時代の enable_if]

それでは C++03 のコードをベースに C++11 に対応していきましょう。

[std::enable_if を使う]

C++11 では標準ライブラリに enable_if が入ったため、Boost に依存することなく enable_if が使用できるようになりました。
ついでに boost::is_integral も標準ライブラリ入りしたのでそれも使用するように変更します。

typename boost::enable_if<boost::is_integral<T> >::type* = 0

typename std::enable_if<std::is_integral<T>::value>::type* = 0

ここで注意なのは boost::enable_if の場合は内部で ::value が展開されていたんですが、std::enable_if の場合は型ではなくて値(::value)を渡す必要があります。
boost::enable_if から std::enable_if にコードを変更する場合にはこのことに注意してください。

[関数テンプレートのデフォルト引数で enable_if を定義]

C++11 では関数テンプレートでも『テンプレート型のデフォルト引数』を定義できるようになりました。 ですので、関数の引数ではなくて『関数テンプレートのデフォルト引数』で enable_if を定義する事が出来ます。

template<
    typename T,
    // nullptr を受け取るのがポイント
    typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr
>
void
func(T t){
    std::cout << t << "は整数だよ" << std::endl;
}

基本的に関数の引数で定義してた時と同じような感じですが、0 ではなくて nullptr をデフォルト値として渡しています。
また、enable_if の第二引数は ::type で返す方を指定できるため std::nullptr_t を渡してします。
これがポイントなんですが nullptr で受け取る理由は以下の記事を参照してください。

この時に enable_if の第二引数に std::nullptr_t 型を渡しているのもポイントなんですが、個人的には

typename std::enable_if<std::is_integral<T>::value>::type* = nullptr

みたいに省略しても基本的には問題ないと思います。
また、他には enabler というイディオムを利用することもあります。

// enable_if で使用するためのダミーの変数を『宣言』しておく
extern void* enabler;

template<
    typename T,
    // nullptr の変わりに enabler を渡す
    typename std::enable_if<std::is_integral<T>::value>::type*& = enabler
>
void
func(T t){
    std::cout << t << "は整数だよ" << std::endl;
}

[C++11 のまとめ]

#include <utility>
#include <iostream>

template<
    typename T,
    typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr
>
void
func(T t){
    std::cout << t << "は整数だよ" << std::endl;
}

void
func(...){
    std::cout << "引数は整数じゃないよ" << std::endl;
}


int
main(){
    func(10);       // 10は整数だよ
    func('c');      // cは整数だよ
    func(3.14f);    // 引数は整数じゃないよ
    return 0;
}

http://melpon.org/wandbox/permlink/gTyeZk1qGdyYogV5

[C++14 時代の enable_if]

C++14 ではさらに enable_if の alias templates である enable_if_t というメタ関数が標準ライブラリに追加されました。
この enable_if_t を使用することで typename::type を省略する事ができるようになります。

typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr

std::enable_if_t<std::is_integral<T>::value, std::nullptr_t> = nullptr

また、alias templates 自体は C++11 で実装された機能なので、以下のように定義しておけば C++11 でも使用することが出来ます。

template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;

参照:std::enable_if - cppreference.com

[C++17 時代の enable_if]

よくわからんので誰か書いて。

[まとめ]

まとめると最新版の enable_if を使ったコードはこうじゃ。

#include <type_traits>
#include <iostream>

template<
    typename T,
    std::enable_if_t<std::is_integral<T>::value, std::nullptr_t> = nullptr
>
void
func(T t){
    std::cout << t << "は整数だよ" << std::endl;
}

void
func(...){
    std::cout << "引数は整数じゃないよ" << std::endl;
}


int
main(){
    func(10);       // 10は整数だよ
    func('c');      // cは整数だよ
    func(3.14f);    // 引数は整数じゃないよ
    return 0;
}

http://melpon.org/wandbox/permlink/7WmFlkGJQ94yVRAU

と、言う感じで各時代の enable_if の使い方をまとめてみました。
enable_if を使った SFINAE はメタプログラミングをする C++er に取っては一般的なテクニックだと思いますが、結構時代によって書き方が変わってきていますね。
今回は enable_if の記事だったのであまり SFINAE には突っ込みませんでしたが、SFINAE を使ったテクニックも時代によって変わってきているので、気になる方は調べてみるとよいと思います。
また、他に『enable_if はもっとこうしたほうが簡単に書けるよ!』みたいなツッコミがあればぜひ教えてもらえると助かります。
あと C++17 はよくわからないので誰か書いてください。 C++17 だと constexpr if があるのでそもそも enable_if が要らなくなるという話もある

[おまけ]

ちなみに enable_if の第二引数には ::type が返す型を指定することが出来ます(デフォルトでは void 型を返す。
ですので関数定義時に戻り値型が決まっているなら次のように『戻り値型』に enable_if を定義することもできます。

template<
    typename T
>
// 戻り値型が void ならそのまま enable_if::type を戻り値型に
typename std::enable_if<std::is_integral<T>::value>::type
func(T t){
    std::cout << t << "は整数だよ" << std::endl;
}

template<
    typename T
>
// 任意の型を返す場合は enable_if の第二引数に渡す
typename std::enable_if<std::is_integral<T>::value, int>::type
plus10(T t){
    return t + 10;
}

template<
    typename T
>
// もちろん enable_if_t を使用して typename と ::type を省略することも
std::enable_if_t<std::is_integral<T>::value, T>
twice(T t){
    return t + t;
}

これは C++03 でも有効なのでデフォルト引数で定義したくない方は使ってみるとよいと思います。

【初心者C++er Advent Calendar 2016 13日目】予約済み識別子に注意しよう

初心者C++er Advent Calendar 2016の13日目が空いてるようなの書きました。
本記事は初心者C++er Advent Calendar 201613日目の記事になります。
初心者C++er Advent Calendar 2016では 3回目の記事になりますが、今回は予約済み識別子の話です。

[予約済み識別子とは]

『予約済み識別子』とは『言語仕様』や『処理系』などで使用するために予約されている識別子のことです。
C++ では以下の3つのいずれかを満たす名前が『予約済み識別子』として予約されています。

  • グローバルスコープを持ち、_ で始まる名前
  • _ で始まり、その次が大文字の名前
  • __ を含む名前

例えば、__LINE__ みたいな定義済みマクロの名前であったり、処理系依存であれば msvc の _MSC_VER 定義済みマクロがそれにあたります。
要は『__ を含む名前とかはコンパイラやライブラリの実装で使う可能性があるからユーザは使わないでねー』というためのものですね。
ですので、以下のようなコードは未定義の動作になります。

// インクルードガードなどで名前の先頭に _ をつけてるのでダメ
#ifndef _INCLUDED_PATH_TO_
#define _INCLUDED_PATH_TO_

#endif

// _ から始まってる名前なのでダメ
typedef struct _X {
    // __ が含まれてる名前なのでダメ
    int value__;
} X;

インクルードガードのマクロ名に『_ から始まってる名前』を使ってるコードをよく見かけますが、これも厳密にいえば未定義の動作になります。

[まとめ]

実際のところ予約済み識別子を使ったところでそこまで問題になる可能性は低いと思います。
しかし、わざわざ未定義の動作になる可能性があるコードを書く必要もないので、C++ を書くときは注意するとよいと思います。 言語によっては _value みたいに『先頭に _ をつける事』を推奨してることもありますが、C++ では基本的に避けるべきです。
ですので、C++ では以下のように『名前の末尾に _ をつけること』が多いです。

// だめ
auto _value = 42;

// おっけー
auto value_ = 42;

こんな感じで基本的には名前の先頭に _ をつけるのを避けるように気をつければ問題ないと思います。
以上で、予約済み識別子の説明は終了です。
予約済み識別子警察には気をつけましょう。

[余談]

Vim を使ってる人は以下のプラグインをいれてみるといいと思います。

[参照]

RSpec のマッチャで === を使う

通常 eq を使用すると == が使われるんですが、これを === で比較したかった。 このように任意の演算子でテストしたい場合は次のように書ける。

expect(9).to be > 6
expect(3).to be <= 3
expect(1).to be < 6
expect('a').to be < 'b'
expect(String).to be === "hoge"

これは知らなかったので便利。

[参照]

【初心者C++er Advent Calendar 2016 8日目】関数テンプレートと関数オブジェクト

タイトルは釣りです。
初心者C++er Advent Calendar 2016 8日目の記事になります。
8日が空いていたので簡単なものを書きます。
前回の記事を書いたあとに

と、言われたので今回はその捕捉になります。

[関数テンプレート]

前回『残念ながら関数の引数型で auto を使用して型推論を行うことは出来ません』と書きました。
確かに auto を使用して型推論を行うことは出来ませんが、template を使用して型推論を行うことは出来ます。

template<typename A, typename B>
auto
plus(A a, B b){
    return a + b;
}

plus(1, 2);       // int + int = int
plus(1, 3.14f);   // int + float = float
plus(std::string("homu"), std::string("mami"));  // std::string + std::string = std::string

こんな感じに auto ではなくて template を使用して引数型を推論する形になります。 基本的な挙動はラムダ式と同じになります。

[関数テンプレートの問題点]

これだけじゃ味気ないのでもうちょっと突っ込んで関数テンプレートの場合の問題点を上げます。
さて、次のように std::for_eachラムダ式を利用して値を出力することが出来ます。

auto output = [](auto x){ std::cout << x << std::endl; };

std::vector<int> xs = {1, 2, 3, 4, 5};
std::for_each(std::begin(xs), std::end(xs), output);

しかし、これを関数テンプレートで行おうとするとエラーになります。

template<typename T>
void
output(T t){
    std::cout << t << std::endl;
}

std::vector<int> xs = {1, 2, 3, 4, 5};

// error: no matching function for call to 'for_each'
std::for_each(std::begin(xs), std::end(xs), output);

これは関数テンプレートを値として使用する場合に『テンプレートの型を明示する』必要があるためです。
ですので、関数などに関数テンプレートを渡す場合は次のようにテンプレートの型を明示する必要があります。

template<typename T>
void
output(T t){
    std::cout << t << std::endl;
}

std::vector<int> xs = {1, 2, 3, 4, 5};

// output<int> を明示する
std::for_each(std::begin(xs), std::end(xs), output<int>);

これで解決します。

[関数オブジェクトを使用する]

さて、関数テンプレートのテンプレート型を明示化することで解決しましたが、毎回型を記述するのは手間です。
そこで、関数ではなくてクラスを利用して回避します。

// operator () を定義したクラスを定義する
struct output_{
    template<typename T>
    void
    operator ()(T t) const{
        std::cout << t << std::endl;
    }
};

// そのクラスのオブジェクトを用意する
output_ const output;

std::vector<int> xs = {1, 2, 3, 4, 5};
// あたかも関数のように振る舞うオブジェクト
std::for_each(std::begin(xs), std::end(xs), output);

関数ではなくてメンバ関数として定義することで型を明示化しなくてもよいようになります。
また、このように operator () を定義して関数のように振る舞うオブジェクトのことを一般的に関数オブジェクトと呼びます。

[まとめ]

よく『template は難しい』みたいなことを聞きますが、やってることは単なる型推論なだけなので auto を理解してるのであれば template に置き換えるだけなのでそんなに難しくはないと思います。
auto にしてもそうですが template を使用することでどんどん型による依存を減らして行くことが可能になります。

【初心者C++er Advent Calendar 2016 3日目】C++ で型推論(auto)しよう

初心者C++er Advent Calendar 2016 3日目の記事です。 3日目が空いてるようなので書いてみました。 今回は初心者向けの Advent Calendar ということで軽めの記事になります。
また、本記事では C++14 を基準としたコードになります。

[C++ で型を書く場面]

さて、C++ は静的型付言語なので、いろんな場面で intfloatstd::string などと言った型を書くことが多いです。

// 関数の戻り値型や引数型
int
func(std::string, float);

// 変数の宣言時に型を指定する
int a = func(std::string("homu"), 3.14f);

今回はこれらの型を auto を使用して省略できる場面を紹介したいと思います。

[変数の宣言時に auto を使う]

変数の宣言時に auto を使用することで右辺値から型推論をしてコンパイラが自動的に型を割り当てます。

// 代入式の右辺値である 42 からコンパイラが型を推論して自動的に型を割り当てる
// 42 は int 型なので n は int 型になる
auto n = 42;

// f は float 型である
auto f = 3.14f;

std::vector<int> v;

// it は std::vector<int>::iterator 型になる
auto it = std::begin(v);

このように本来は

std::vector<int>::iterator it = std::begin(v);

というように型が長くなってしまう場合、auto を利用することで

auto it = std::begin(v);

という風に簡略化することが出来ます。
また、当然ですがこの場合は『変数の初期値』を指定する必要があります。

[戻り値型を auto にする]

関数の戻り値型を auto にすることで return 文などからコンパイラが自動的に戻り値型を推論します。

// この関数の戻り値型は int 型 + float 型の結果(float 型)になる
auto
plus(int a, float b){
    return a + b;
}

// 複数の return をする場合は『同一の型』を return する必要がある
auto
func(int flag){
    if( flag ){
        return std::string("OK");
    }
    else {
        // コンパイル時に型を決定する必要があるので違う型を return することは出来ない
        // return -1
        return std::string("NG");
    }
}

// 戻り値を省略した場合は void 型になる
auto
hello_world(){
    std::cout << "hello, world" << std::endl;
    // こっちでもおk
//     return;
}

このように戻り値型に auto を使用することが出来ます。
注意点としては必ず『同じ型の値を return する』ということですね。
また、残念ながら関数の引数型で auto を使用して型推論を行うことは出来ません。

[ラムダ式の引数で auto を使用する]

先ほど関数の引数では auto は使えないと書きましたが、実はラムダ式の引数であれば auto を使用する事が出来ます。

// 引数型を auto にすることでどんな型でも受け取ることができる
auto output = [](auto a) { std::cout << a << std::endl; };
output(42);
output("homu");
// std::vector<int> も渡すことはできるが、std::cout に対応してないのでエラー
// output(std::vector<int>{});


// 戻り値型の auto と組み合わせて使用することもできる
// この場合、戻り値型は引数型に依存する
auto plus = [](auto a, auto b) -> auto { return a + b; };

plus(1, 2);       // int + int = int
plus(1, 3.14f);   // int + float = float
plus(std::string("homu"), std::string("mami"));  // std::string + std::string = std::string

ラムダ式の場合、引数型によって戻り値型が変わるというのが面白いですね。
C++ では で定義されてる関数にラムダ式を渡すことが多いので、このように引数型を型推論できることでかなり使い勝手がよくなると思います。

[まとめ]

C++ では複雑な型を扱うことが多いのですが、このように auto を使用することで冗長なコードをすっきり記述できる場面が多いです。
また、今回は使用しませんでしたが template を使用することで更に型を省略することも出来ます。
ただ、C++ では『型について理解することも重要』なので初心者の方はまず最初に『どんな型として扱わるのか』と考えてみましょう。
この関数の戻り値型は何か、式を演算した結果何型を返すのか、暗黙の型変換とは etc...と C++ で型について考えることは尽きません。
その上で型に慣れてきたら auto を使ってみるとよいと思います。
そんな感じでざっくりとして内容ですが 初心者C++er Advent Calendar 2016 3日目の記事になります。

[参照]

【Ruby Advent Calendar 2016 1日目】 Ruby でブロックを簡潔に定義する

Ruby Advent Calendar 2016の1日目の記事になります。
わたしはあまり Rails と言ったフレームワークRuby がよく利用されてる Web 界隈には詳しくはないので、本記事は Ruby という言語に関するネタになります。

[Ruby といえば]

さて、表題のブロックですが、Ruby といえばブロック、ブロックといえば Ruby というぐらい Ruby という言語を語る上では切っては切れない機能の一つになります。
特に #map#select などと言ったリスト操作とブロックの組み合わせは Ruby を書く上での醍醐味と言っても過言ではないと思います。

[ブロックの不満点]

そんな Ruby では多用されるブロックですが、コードを書く上で少し不満点があります。
例えば次のようなコードをみてみましょう。

["foo", "bar", "baz"].map { |it| it.upcase }
#=> ["FOO", "BAR", "BAZ"]

コード自体は特に問題はないのですが、ブロックで引数を受け取る関係上 it を2回も記述する必要があります。
こちらでも書かれていますが、Ruby を書いていると『こういう簡単なブロック』を書くことが多くあり無駄に感じます。
なにより簡潔ではありません。
あと単純にブロック自体書くのがめんどくさいです。

[Symbol#to_proc を利用する]

ここで Ruby に精通する人はピンと来ると思いますが、上記のブロックのように『レシーバのメソッドを呼び出すだけ』のブロックは次のように Symbol#to_proc を利用して書き換えることが出来ます。

# 第一引数の #upcase を呼び出すブロックとして処理される
["foo", "bar", "baz"].map &:upcase
#=> ["FOO", "BAR", "BAZ"]

おお、これなら簡潔に記述することができるじゃないか!
と、思いますが、残念ながらこのテクニックは次のような場合に利用出来ません。

# 引数メソッドに引数を渡す場合
["0x12", "0x34", "0x56"].map { |it| it.to_i(16) }
# => [18, 52, 86]

# 呼び出すメソッドをチェーンする場合
[:foo, :bar, :baz].map { |it| it.to_s.upcase }
# => ["FOO",  "BAR",  "BAZ"]

この場合は Symbol#to_proc を使用して簡潔に定義することはできませんね。

NOTE: instance method Symbol#to_proc (Ruby 2.3.0)

生成される Proc オブジェクトを呼びだす(Proc#call)と、 Proc#callの第一引数をレシーバとして、 self という名前のメソッドを 残りの引数を渡して呼びだします。

[lambda_driver ではどうか]

ブロックを簡潔に定義するといえば lambda_driver という有名な gem が存在します。
lambda_driver についてはこちらに詳しく書かれています。
lambda_driver は Symbol と複数の記号を組み合わせることで関数合成などを抽象化して定義することができます。

# [:foo, :bar, :baz].map { |it| it.to_s.upcase }
[:foo, :bar, :baz].map(&:to_s >> :upcase )
# => ["FOO",  "BAR",  "BAZ"]

これは確かに便利だとは思います。
しかし、全く知らない人から見ると式が抽象化され過ぎてて難読化するのがやや気になります。
例えば、次のようなコードは記号が多用されており、パッと見なにをやっているのかわかりづらいです。

# [:foo, :hoge, :bar, :fuga].select{|s| s.to_s.length > 3}
[:foo, :hoge, :bar, :fuga].select(&:to_s >> :length >> 3._(:<))
# => [:hoge, :fuga]

以上を踏まえて、Ruby で簡潔にブロックを定義する方法を考えていきたいと思います。

[Ruby 以外の言語に目を向ける]

もっと簡潔に定義できる方法はないか考えてみましょう。
こういう時は Ruby 以外の言語を参考にしてみるのもひとつの手です。
そんなわけで今回は C++ にちょっと目を向けてみます。
Ruby を書いてる人にはちょっと馴染みがないかも知れませんが、C++ に Boost というメジャーなライブラリがあります。
この Boost はいくつかのライブラリが 1つにまとまったものになるのですが、その中に Boost.Lambda というライブラリがあります。
Boost.Lambda とはその名の通り『C++ で簡潔にラムダ式を定義する』ために考えだされたライブラリです。
使い方自体はそんなに難しくなくて、簡単に説明するとプレースホルダというものを引数に置き換えるような形でラムダ式を定義します。

// _1 や _2 などは該当する引数の順番に置き換えられる
auto plus3 = _1 + 3;
plus3(2); // => 5

auto sum = _1 + _2 + _3;
sum(1, 2, 3); // => 6

auto is_even = _1 % 2 == 0;
is_even(2);  // true
is_even(-3); // false

NOTE: 無名関数 - boostjp

C++ をよく知らないという人でもなんとなく使い方のイメージはできると思います。
と、いうことで Ruby でもこんな感じでブロックを定義してみよう!というのが今回の本題です。

[プレースホルダをつくる]

さて、まずはプレースホルダを定義していきたいと思います。
今回定義するプレースホルダは以下のような性質をもたせます。

# n 番目の引数の値を返す
_1.(1, 2, 3)
# => 1
_2.(1, 2, 3)
# => 2
_3.(1, 2, 3)
# => 3

これを以下のように実装していきます。

class Lazy
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end
end


def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

# n 番目の引数の値を返す
_1.(1, 2, 3)
# => 1
_2.(1, 2, 3)
# => 2
_3.(1, 2, 3)
# => 3

Lazy#call が呼ばれたら Lazy.new 時に渡しがブロックが呼び出される構造になります。
今回は Proc クラスを拡張したくなかったので Lazy というクラスで薄くラップして拡張していきます。

[メソッドの呼び出しを遅延評価する]

次にプレースホルダから遅延してメソッドを呼びだせるように #__send_delay__ というメソッドを定義します。 イメージとしては以下のような感じです。

# 第一引数に対して #upcase を呼び出す
to_upcase = _1.__send_delay__(:upcase)

# このタイミングで引数に対して #upcase が呼ばれる
to_upcase.("homu")
# => "HOMU"

to_hex = _1.__send_delay__(:to_s, 16)
to_hex.(42)
# => "2a"

このように『あとで #call が呼び出された時』に指定したメソッドが評価されるようにします。

class Lazy
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        # Lazy オブジェクトを返す
        Lazy.new { |*args_, &block_|
            call(*args_, &block_).__send__(name, *args, &block)
        }
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

# 第一引数に対して #upcase を呼び出す
to_upcase = _1.__send_delay__(:upcase)

to_upcase.("homu")
# => "HOMU"

to_hex = _1.__send_delay__(:to_s, 16)
to_hex.(42)
# => "2a"

ここで肝なのが『#__send_delay__Lazy オブジェクトを返す』ところです。
これにより『メソッドをチェーンして』遅延評価することが出来ます。

to_upcase_hex = _1.__send_delay__(:to_s, 16).__send_delay__(:upcase)
to_upcase_hex.(20161201)
# => "133A2B1"

いい感じです。 ただ、毎回 #__send_delay__ を呼び出すのはやや冗長ですね。

[method_missing を経由して #__send_delay__ を呼び出す]

さて、こんな時はメタプログラミングの出番です。
Ruby には『レシーバに存在しないメソッドを呼び出した時に処理をフックする』ことが出来ます。 この時に定義するメソッドが #method_missing になります。 これを利用することで #__send_delay__ を経由することなく、自然にメソッドの遅延処理を定義することが出来ます。

NOTE: instance method BasicObject#method_missing (Ruby 2.3.0)

呼びだされたメソッドが定義されていなかった時、Rubyインタプリタがこのメソッド を呼び出します。

class Lazy
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        ::Lazy.new { |*args_, &block_|
            call(*args_, &block_).__send__(name, *args, &block)
        }
    end

    # method_missing 経由で #__send_delay__ を呼び出す
    def method_missing name, *args, &block
        __send_delay__ name, *args, &block
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

# プレースホルダをレシーバとして直接メソッドを呼び出すことができる
to_upcase = _1.upcase
to_upcase.("homu")
# => "HOMU"

to_upcase_hex = _1.to_s(16).upcase
to_upcase_hex.(20161201)
# => "133A2B1"

こんな感じで『プレースホルダをレシーバとして直接メソッドを呼び出す』ことができるようになりました。 かなり自然にメソッドの呼び出しを書けるようになりましたね。
そして Ruby では『演算子もメソッド』であるため、以下のように演算子も定義することも出来ます。

# _1.+(3) と同等
plus3 = _1 + 3
plus3.(5)
# => 8

NOTE: クラス/メソッドの定義 (Ruby 2.3.0)

演算子式において、「再定義可能な演算子」に分類された演算子の実装 はメソッドなので、定義することが可能です。

これは素晴らしい。
ちなみに #method_missing を利用したかったのが『Proc クラスを拡張しなかった』理由の一つです。

[Object で定義されているメソッドは #method_missing で呼び出されない]

さて、これにより『Lazy クラスで定義されていないメソッド』は #method_missing を利用することで簡潔に呼び出す事ができるようになりました。 しかし、 通常 Ruby ではクラスを定義した場合は内部で Object クラスが自動的に継承されるため、デフォルトでも多数のメソッドが定義されています。

NOTE: class Object (Ruby 2.3.0)

全てのクラスのスーパークラス。 オブジェクトの一般的な振舞いを定義します。

ですので次のように『Object クラスで定義されてるメソッド』は #method_missing 経由で呼び出すことは出来ません。

# 第一引数の #class を遅延評価して欲しいが Lazy#class が呼び出されてしまう
_1.class
# => Lazy

[BasicObject を継承して空のクラスを定義する]

今回は Object クラスで定義されてる『多数のメソッドも遅延評価したい』ので Lazy オブジェクトでは定義してほしくありません。
このような場合は BasicObject を継承することで解決することが出来ます。

NOTE: class BasicObject (Ruby 2.3.0)

Object クラスは様々な便利なメソッドや Kernel から受け継いだ関数的メソッド を多数有しています。 これに対して、 BasicObject クラスはオブジェクトの同一性を識別したりメソッドを呼んだりする 最低限の機能の他は一切の機能を持っていません。

明示的に BasicObject クラスを継承することで、最低限のメソッドのみが定義されているクラスを定義することが出来ます。

# BasicObject を継承することで最低限のメソッドのみ定義するようにする
class Lazy < BasicObject
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        ::Lazy.new { |*args_, &block_|
            call(*args_, &block_).__send__(name, *args, &block)
        }
    end

    def method_missing name, *args, &block
        __send_delay__ name, *args, &block
    end

    # BasicObject では #== が定義されているので、Lazy の性質に合わせて再定義する
    def == *args, &block
        __send_delay__ :==, *args, &block
    end

    def ! *args, &block
        __send_delay__ :!, *args, &block
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

to_class = _1.class

to_class.("homu")
# => String
to_class.([])
# => Array

また、この時に注意するのが #== など一部のメソッドは BasicObject でも定義されているので用途に合わせて再定義する必要があります。

NOTE: instance method BasicObject#== (Ruby 2.3.0)

このメソッドは各クラスの性質に合わせて、サブクラスで再定義するべきです。 多くの場合、オブジェクトの内容が等しければ真を返すように (同値性を判定するように) 再定義 することが期待されています。

このあたりのテクニックは #method_missing を使用する際は覚えておくとよいです。

[引数にプレースホルダを渡す]

さて、次に『遅延評価するメソッドの引数にプレースホルダを渡す』ことを考えてみましょう。
以下のようにメソッドの引数にもプレースホルダを渡したいですよね。

# #to_s の引数は第二引数で受け取るようにする
to_s = _1.to_s(_2)

to_s.(42, 2)
# => "101010"

ですので、Lazy オブジェクトを『再帰的に評価する』ように修正します。

class Lazy < BasicObject
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        ::Lazy.new { |*args_, &block_|
            # 式を組み立てるときに渡された引数が Lazy オブジェクトであれば評価する
            apples = args.map { |it| ::Lazy === it ? it.call(*args_, &block_) : it }
            call(*args_, &block_).__send__(name, *apples, &block)
        }
    end

    def method_missing name, *args, &block
        __send_delay__ name, *args, &block
    end

    def == *args, &block
        __send_delay__ :==, *args, &block
    end

    def ! *args, &block
        __send_delay__ :!, *args, &block
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

to_s = _1.to_s(_2)

to_s.(42, 2)
# => "101010"
to_s.(42, 16)
# => "2a"

こんな感じです。
ちょっとわかりづらいかもしれませんが、要は『#to_s の引数が Lazy だったら先に評価する』ようにしてるだけですね。
これにより次のような演算子を使った式も簡潔に定義できます。

expr = _1 + _2 * _3
expr.(1, 2, 3)
# => 7

実にわかりやすいですね。

[プレースホルダの弱点]

この便利そうなプレースホルダですが、1つだけ弱点があります。
それは『プレースホルダをレシーバとして呼び出す』必要があることです。
どういうことかというと例えば、

_1 + "homu"

という風に式を記述することは出来ますが、

"homu" + _1

という風に左辺値にプレースホルダ以外を置いた場合、Lazy オブジェクトとして定義することは出来ません。
なぜなら #+String クラスで定義されており、Lazy クラスは干渉出来ないからです。
これを解決したい場合、Ruby では String#+ を拡張するという手段はあるんですが、型のない言語で『特定のクラスに対する処理』というのはあまりやりたくありません。

[Object#to_lazy を定義する]

そこで今回は Object#to_lazy というヘルパメソッドを定義して解決したいと思います。

class Lazy < BasicObject
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        ::Lazy.new { |*args_, &block_|
            apples = args.map { |it| ::Lazy === it ? it.call(*args_, &block_) : it }
            call(*args_, &block_).__send__(name, *apples, &block)
        }
    end

    def method_missing name, *args, &block
        __send_delay__ name, *args, &block
    end

    def == *args, &block
        __send_delay__ :==, *args, &block
    end

    def ! *args, &block
        __send_delay__ :!, *args, &block
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

class Object
    # 自身を Lazy のオブジェクトとして返す
    def to_lazy
        Lazy.new { self }
    end
end

# 任意のオブジェクトのメソッドを遅延評価できる
homu_plus = "homu".to_lazy + _1
p homu_plus.("mami")
# => "homumami"

ary = [1, 2, 3]
add = ary.to_lazy << _1
add.(1)
add.(2)
add.(3)
p ary
# => [1, 2, 3, 1, 2, 3]

Object#to_lazy は単に『自身を返す Lazy オブジェクト』を返すだけです。
これで任意のメソッドを遅延評価することができるようになりました。

[ブロックに渡せるように #to_proc を定義する]

最後にブロックに渡せるように #to_proc を定義します。
Ruby では #to_proc を定義することでそのオブジェクトをブロックに渡せるようになります。

class Lazy < BasicObject
    def initialize &block
        @block = block
    end

    def call *args, &block
        @block.call *args, &block
    end

    def __send_delay__ name, *args, &block
        ::Lazy.new { |*args_, &block_|
            apples = args.map { |it| ::Lazy === it ? it.call(*args_, &block_) : it }
            call(*args_, &block_).__send__(name, *apples, &block)
        }
    end

    def method_missing name, *args, &block
        __send_delay__ name, *args, &block
    end

    def == *args, &block
        __send_delay__ :==, *args, &block
    end

    def ! *args, &block
        __send_delay__ :!, *args, &block
    end

    # #to_proc を定義することにより Lazy オブジェクトをブロック引数として渡せる
    def to_proc
        ::Proc.new { |*args, &block| call *args, &block }
    end
end

def placeholder index
    Lazy.new { |*args| args[index] }
end

_1 = placeholder 0
_2 = placeholder 1
_3 = placeholder 2

class Object
    def to_lazy
        Lazy.new { self }
    end
end


# ブロックに直接 Lazy オブジェクトを渡せる
p (1..10).map &_1.to_s(2)
# => ["1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010"]

# こんな感じで定義することもできる
evens = _1.select(&_1 % 2 == 0)
p evens.(1..10)
# => [2, 4, 6, 8, 10]

# Kernel のメソッドも遅延評価できる
(1..10).each &to_lazy.puts(_1)

これで一応完成になります。

[他のコードと比較してみる]

lambda_driver などと比較してみるとこんな感じです。

# default
[:foo, :bar, :baz].map { |s| s.to_s.upcase }
# or
[:foo, :bar, :baz].map(&:to_s).map(&:upcase)
# => ["FOO",  "BAR",  "BAZ"]

# lambda_driver
[:foo, :bar, :baz].map(&:to_s >> :upcase)

# placeholder
[:foo, :bar, :baz].map(&_1.to_s.upcase)


# default
[:foo, :hoge, :bar, :fuga].select { |s| s.to_s.length > 3 }
# => [:hoge, :fuga]

# lambda_driver
[:foo, :hoge, :bar, :fuga].select(&:to_s >> :length >> 3._(:<))

# placeholder
[:foo, :hoge, :bar, :fuga].select(&_1.to_s.length > 3)


# default
def twice n
    n + n
end

puts twice(65).to_s.length

# lambda_driver
_.twice >> :to_s >> :length >> _.puts < 65

# lambda_driver に合わせて to_lazy を短くする
alias _ to_lazy
_.puts(_.twice(_1).to_s.length).(65)

プレースホルダを使用することでかなり簡潔にブロックを定義できるようになったと思います。

[唯一の弱点]

さて、ほぼやりたいことはできたんですが、1つだけどうしても出来ないことがあります。
それは && 演算子|| 演算子の遅延評価です。
例えば、

cond = _1 >= 5 && _1 <= 10

みたいな式を定義したい場合、これでは上手く動作しません。
これは +[] 演算子などはメソッドとして扱われますが、&&||Ruby 本体の制御構造として扱われる為です。
Ruby では &&|| などの演算子の再定義も禁止されています。
つまり上記の場合は && の左辺値(5 <= _1) が真になるため、cond には 5 <= _1 が代入されます。
この性質は Ruby の言語仕様上の問題なので現状はどうすることも出来ません。

NOTE: 演算子式 (Ruby 2.3.0)

[まとめ]

そんな感じでいい感じにブロックを簡潔に定義できるようになりました。
なんか1日目からガッツリと書いてしまって重くないか心配です。
最初にも書きましたが Ruby ではどうしてもブロックを多用する言語なので、そのブロックが簡潔に定義できることはかなり便利です。
またこういう『他の言語から影響を受けて実装する』というのはなんか他の言語のいいとこ取りをしている感じがしているのでいいですね、どんどんパクっていきましょう。 特に Ruby は柔軟な言語なのでメタプログラミングでサクッと実現できることが多いので書いていて楽しいです。
Ruby といえば Rails というイメージですが、Ruby 単体でも十分に面白い言語なのでみんな使ってみるといいです。Ruby = Rails と思ってるやつしねばいいのに
もうすぐ Ruby 2.4 もリリースらしいですし、将来的に Ruby に型システムを導入するみたいな話出ていますし、今後は他の言語と比べてどういう風に進化していくのかが楽しみですね。

ちなみに今回実装したコードは ioliteというライブラリで gem 化してます。
使い方などは基本的に同じですが、つくったのが結構前なのでだいぶレガシーなコードで味わい深いです。
興味がある人は example やここなどみてみると面白いです。
そんな感じで2日目に続きます。