エラーハンドリングを綺麗にこなすためのライブラリ・expectedの紹介と応用

この記事は[C++ Advent Calendar 2016](http://www.adventar.org/calendars/1527)の20日目の記事です．
昨日は[春野すずらん](https://twitter.com/latte_suzuran)さんの『[c++ で少し便利かもしれない行列ライブラリと超複素数ライブラリ作ってみた。](http://qiita.com/latte_suzuran/items/c1a25ab27828f950bea9)』でした．

---

　I([@wx257osn2](https://twitter.com/wx257osn2))です．今年は教育実習だの卒研だのいろいろやってたら終わってしまった1年でした．そろそろのんびり生きたい．

**追記(12/31)** : なんとか年内に書き終わりました…大幅に遅れてしまい大変申し訳…

# **おことわり**
　当記事におけるC++とはバージョンの記載が無い場合主にC++1zを指します．また，当記事におけるWinAPIとはCOMなども含むWindowsで使用できるAPI全般を指すものとします．そして，後半ではVS2017RC[^VS2017TPL]を使っておりますので，後半のコードを手元で動作させたい，という方は予めご用意ください．加えて，コードは記事掲載時点のコンパイラ・ライブラリを使用したものですので，将来的には動かなくなる可能性があります[^will_broken_change]．ご了承ください．

[^VS2017TPL]: そういえば，VSにTPLくるらしいですね．やったぜ．
[^will_broken_change]: 特に後半で出てくる自作のライブラリはインターフェースの破壊的変更をしまくっているので(やめろ)，大体コミット毎にそれまでのコードが通らなくなります…

# **tl;dr**
　正常値とエラー値のいずれかを格納する型・`expected`の紹介と，実際に応用した際にどの程度効果があるか，そしてその限界について見ていきます．一言で言えば，`expected`はいいぞ．

# **はじめに**
　今年も1年いろいろなことがあったと思います[^bun]．技術界隈では記憶に新しいものとして，言語を跨いで話題になった単語で「null安全」なるものがありましたが，皆さんご存じでしょうか？

[^bun]: 鳥頭なのであんまり覚えてないんですけど．

## **null安全 #とは**
　『[null安全でない言語は、もはやレガシー言語だ](http://qiita.com/koher/items/e4835bd429b88809ab33)』という記事[^non-null-safety_is_legacy]を発端[^beginning]として一時期巷で騒がれていた単語です．記事中では，以下のような定義付けが為されています．
> 言語によって Optional や Option, Maybe, nullable type などの型で実現できる、 null が原因で実行時エラーを起こさない性質のこと

なるほど，確かにnull安全はあったほうがうれしいですね．**null安全な言語機能・ライブラリを使うとコードが綺麗になります．**C++にもC++1zより`std::optional<T>`が入り，Boostを入れずともnull安全なコードが実現出来るようになります．

[^non-null-safety_is_legacy]: ところで，記事中ではC++はレガシーなコードベースがたくさんあって全部を`std::optional<T>`に対応させるのは現実的ではないからnull安全ではないレガシー言語，とされていますが，「**うるせぇラッパーを書けよ**」という感想です．そもそもコードベース全部使うわけでもないし，コードベースの無い言語で一から作るよりはラッパー書いた方が早いんじゃないかと思います，知らないですけど．あと，`boost::optional<T>`の登場からもう10年以上経ってるので，対応してないコードベースがクソなだけだと思うしそんなクソコードさっさと捨てた方がいいと思います(適当)
[^beginning]: 私はそういう認識なんですけど合ってますかね？

### **null安全は本当にうれしいのか**
　さて，突然前言をひっくり返しますが，本当にnull安全ってうれしいのでしょうか？[^makes_happy]もちろんnull安全か否か，と言われればnull安全の方がうれしいのは確かです．でも，**本当にnull安全で十分でしょうか？**
　そもそもnull安全の文脈における「null」ってなんなのでしょうか．

```cpp
#include<sstream>
#include<optional>

std::optional<int> read_int(std::istream& is){
  int t;
  if(is >> t)
    return t;
  return std::nullopt;
}

#include<iostream>

void test(std::istream& is){
  auto u = read_int(is);
  std::cout << u.has_value();
  if(u)
    std::cout << " : " << *u;
  std::cout << std::endl;
}


int main(){
  std::cout << std::boolalpha;
  {
    std::stringstream ss;
    test(ss); //false
  }
  {
    std::stringstream ss;
    ss << 30;
    test(ss); //true : 30
  }
}
```
```
false
true : 30
```
null安全における「null」(ここでは`std::nullopt`)とは，「処理に失敗したことを表す値」のはずです．しかし現実として，「処理に失敗したことを表す値」は果たして`null`(C++で言えば`nullptr`)だけでしょうか？C++(とC++でよく使われるAPI)で考えてみてもパッと

- `nullptr`
- `false`
- `-1`など不正を表す実装定義の値
    - `GetLastError()`や`errno`などエラー情報の取得を別で行う必要がある物もある
- `FAILED(hr)`(`HRESULT`型の値のうち不正値を表すもの)
- 例外

の5種ぐらいは浮かびます．`std::optional<T>`で実現するnull安全は，これらを全て`std::nullopt`として扱うことで実現されることになります．
　しかし，`GetLastError()`/`errno`と`HRESULT`と例外(と，物によりますが，実装定義の値[^implementation_defined_value])は**エラーの内容を含んでいます**．これらを全て`std::nullopt`にまとめることで，**「なぜ処理に失敗したのか」という情報を捨てることになり**ます．つまり，正常系の記述には十分に有用ですが，異常系の記述に際して正しいエラーハンドリングは期待できないということです．私が思うに，**null安全では不十分[^definition_of_null_safety]**です．

[^makes_happy]: ここで述べる問題以外に，細かなパフォーマンスの低下(の可能性)といった **ゼロオーバーヘッド原則と相反する** 点について[白山風露](https://twitter.com/kazatsuyu)さんの『[null安全な言語は、本当にゼロコストか](http://qiita.com/kazatsuyu/items/a040992c5dff7cfe6537)』で言及されています．
[^implementation_defined_value]: 実装定義の値としてエラーの内容によって異なる値を返すもの．
[^definition_of_null_safety]: ここでいう「null安全」とは，上述の記事で定義されている通り「**Optional や Option, Maybe, nullable type などの型**で実現できる、 null が原因で実行時エラーを起こさない性質のこと」です．


## **エラー情報もうまく扱いたい**
　null安全ではエラーの詳細な情報が握りつぶされてしまうという問題があることがわかりました．これは，**不正値を単一の値で表しているから**です．逆説的に，**不正値としてエラーの詳細を持てばこの問題は解決**します．Haskellには`Either`モナドというものがあり，`Either a b`として失敗(`Left a`)と成功(`Right b`)のいずれか一方を格納する型をつくることができます．我々が本当に欲しかったのはこれです[^nullable_type_is_zako]．
　しかし，C++はレガシーな言語なので，そんな便利なものは無いのでは…なんて思ったそこのアナタ，ちゃんとC++にもあります[^expected_is_not_standard_yet]．それが表題にもある`expected`です．

[^nullable_type_is_zako]: 「顧客が本当に必要だったのはnull安全ではなく`Either`だったんだよ！」   勿論，正常値が特定の型で表され，それとは別に失敗が単一の不正値のみで表現される処理なのであればnullable typeで十分表現が可能です．しかし上述の通り現実としてはエラーの内容を知りたいですし，`Either`相当のものも必要になってきます．ライブラリ実装ではなく言語機能としてnullable typeを提供している言語は同等のサポートをするために態々`Either`相当のものを言語機能として提供する必要に迫られますが，正直これは筋が悪いんじゃねーかと思います(雑感)
[^expected_is_not_standard_yet]: 標準ライブラリにあるとは言っていない．

# **`expected`**
> [ptal/expected: What did you expect?](https://github.com/ptal/expected)
> https://github.com/ptal/expected

　この章では正常値または不正値のいずれかを格納する型`expected`の機能について見ていきます．
この章のコードはグローバル名前空間での`using namespace boost;`を前提とします[^i_dont_wanna_use_using_namespace]．

[^i_dont_wanna_use_using_namespace]: あまり行儀は良くないのですが，後半で名前空間が`boost`ではなくなるのでそこをあまり表に出したくない，という事情からこのようにしました．

## **宣言と初期化**
　`expected<T, E>`で型`T`の正常値または型`E`の不正値を格納する型となります[^right_left]．型`T`の値は`expected<T, E>`へ暗黙変換できます．型`E`の値は`make_unexpected(E)`関数を通す必要があります[^make_unexpected]．また，`expected<T>`とすると`E`にはデフォルト型引数`std::exception_ptr`が入り，**任意の例外をエラー値として扱えるようになります**．

```cpp
expected<double> divide(double num, double den){
  if(den == 0)
    return make_unexpected(std::domain_error("divide by zero"));
  return num / den;
}
```

[^right_left]: Haskellの`Either a b`に対して`expected<b, a>`となるので気をつけましょう．
[^make_unexpected]: `make_unexpected(e)`によって`unexpected_type<E>`型の値となり，これが`expected<T, E>`へ暗黙変換可能．ちなみに，`unexpected_type`が`unexpected`でないのは標準入りさせる段階で[`std::unexpected()`](https://cpprefjp.github.io/reference/exception/unexpected.html)との名前衝突を避けるためだと思われる．

## **正常値かどうかを確認する**
　`expected<T, E>`に入っている値が正常値かどうかを確認するためには，`valid()`メンバ関数を呼びます．

```cpp
std::cout << std::boolalpha << divide(3, 2).valid() << ' ' << divide(3, 0).valid() << std::endl;
```
```
true false
```
また，`expected<T, E>`には`explicit operator bool()`が定義されているので，`if`や`while`の条件式とかでは`valid()`メンバ関数を呼ばなくてもちゃんと中身の判定をしてくれます．

```cpp
auto t = divide(3, 2);
if(t)
  std::cout << "divide(3, 2) is valid" << std::endl;
std::cout << "divide(3, 0) is " << (divide(3, 0) ? "valid" : "invalid") << std::endl;
```
```
divide(3, 2) is valid
divide(3, 0) is invalid
```

## **値を取り出す**
　`expected<T, E>`から正常値を取り出すためには，以下の2通りの方法があります．
### **`value()`メンバ関数**
　中身が正常値かどうかをチェックし，正常値であれば中身を取り出します．エラー値であれば，例外として送出します．

```cpp
std::cout << divide(3, 2).value() << std::endl;
try{
  std::cout << divide(2, 0).value() << std::endl;
}
catch(std::logic_error& e){
  std::cout << e.what() << std::endl;
}
```
```
1.5
divide by zero
```

### **`operator *`**
　**中身が正常値かどうかをチェックすることなく**，正常値であるものとして中身を取り出します．エラー値が入っていた場合の挙動は多くの場合未規定[^unchecked_dereference_may_be_unspecified]です．**値が正常であることが期待できる場合にのみ**使用するべきでしょう．

```cpp
auto t = divide(3, 2);
if(t)
  std::cout << "divide(3, 2) = " << *t << std::endl;
auto s = divide(3, 0);
if(s)
  std::cout << "divide(3, 0) is " << *s << std::endl;
else
  std::cout << "divide(3, 0) is invalid" << std::endl;
//以下は未規定動作なので実行結果に意味はない
std::cout << *s << std::endl;
```
```
divide(3, 2) = 1.5
divide(3, 0) is invalid
1.42051e-316
```

ちなみに，正常値のメンバに対して`operator ->`で直接アクセスすることも可能です．これも中身のチェックはしません．

[^unchecked_dereference_may_be_unspecified]: 正常値とエラー値双方が同じ型である場合(`expected<T, T>`)，`operator *`で**エラー値がチェックなしに取り出せてしまいます(この挙動は言語規格上保証されています)**．

## **エラーを取り出す**
　`expected<T, E>`からエラーを取り出すには，`error()`メンバ関数を使用します．ただし，**`error()`メンバ関数は`operator *`同様中身がエラーであるかをチェックすることなくエラーであるとみなして中身を取り出す**ので，呼び出すときには中身がエラー値であることが分かった状態で呼び出すべきです．[^unchecked_error_example]

```cpp
auto t = divide(3, 0);
if(!t){
  try{
    std::rethrow_exception(t.error());
  }catch(std::logic_error& e){
    std::cout << e.what() << std::endl;
  }
}
```
```
divide by zero
```
[^unchecked_error_example]: 例えば正常値が入った`expected<double>`から`error()`で`std::exception_ptr`を取り出して`std::rethrow_exception(std::exception_ptr)`で例外を再送出しようとした場合，当然参照先はでたらめなのでdangling referenceなどが発生しえます．

## **モナドっぽく使う**
　ひとまずこれで最低限使うことは出来ますが，現状だと「`double`型の変数を文字列に変換して返す，失敗した場合は`"failed"`という文字列のアドレスを返す関数`expected<std::string, const char*> to_str(double)`[^to_str_failed]」を使って「`divide(double, double)`関数の値を文字列に変換し，変換後の文字列の長さを返す」といったプログラムを書きたい場合，以下のようなコードになってしまいます．

```cpp
expected<std::string, const char*> to_str(double t)try{
  return std::to_string(t);
}catch(std::exception&){
  return make_unexpected("failed");
}

expected<std::string::size_type, const char*> func1(double t){
  auto a = divide(3, t);
  if(a){
    auto b = to_str(*a);
    if(b)
      return b->size();
    else
      return make_unexpected(b.error());
  }
  else{
    return make_unexpected("divide by zero");
  }
}
```
**無限にネストするやつだこれ**．もうちょっとなんとかなって欲しいですね．一応，例外を使えばもうちょっとスッキリはします．


```cpp
expected<std::string::size_type, const char*> func2(double t){
  try{
    auto&& a = divide(3, t).value();
    auto&& b = to_str(a).value();
    return b.size();
  }catch(bad_expected_access<const char*>& e){
    return make_unexpected(e.error());
  }catch(...){
    return make_unexpected("divide by zero");
  }
}
```
でも，もうちょっと綺麗に使いたい．そこで，以下のメンバ関数を使用します．

[^to_str_failed]: 現実としてここでコケるのって多分`bad_alloc`だと思うので，その状態で`std::string`を返すのは無謀かなと思ってやめておきました(SSOのことを考えればおそらくどちらも動的メモリ確保は行われなさそうな気もするんですけど)

### **`map(F)`メンバ関数**
　`map(F)`メンバ関数は`T`型の値を受け取る関数`f`を受け取り，中身が正常値なら`f(value())`の結果を，中身が不正値ならそれを返します．`expected<T, E>`から`expected<decltype(f(value())), E>`を得る操作です．

```cpp
divide(3, 2).map([](double t){return int{t};}); //expected<int>{1};
divide(3, 0).map([](double t){return int{t};}); //expected<int>{unexpected_type<>{std::domain_error("divide by zero")}};
```

### **`bind(F)`メンバ関数**
　`bind(F)`メンバ関数は`T`型の値を受け取り`expected<U, E>`(`U`は任意の型)を返す関数`f`を受け取り，中身が正常値なら`f(value())`の結果を，中身が不正値ならそれを返します．`expected<T, E>`から`decltype(f(value()))`(`expected<U, E>`)を得る操作です．

```cpp
divide(3, 2).bind([](double t){return expected<int>{static_cast<int>(t)};}); //expected<int>{1};
divide(3, 0).bind([](double t){return expected<int>{static_cast<int>(t)};}); //expected<int>{unexpected_type<>{std::domain_error("divide by zero")}};
```

### **`then(F)`メンバ関数**
　`then(F)`メンバ関数は`expected<T, E>`を受け取る関数`f`を受け取り，`f`に自身を渡した結果を返します．`f`が`expected<U, X>`(`U`，`X`は任意の型)を返すのであれば`expected<T, E>`から`decltype(f(expected<T, E>{}))`(`expected<U, X>`)を，`f`が`expected`でない型を返すのであれば`expected<T, E>`から`expected<decltype(f(expected<T, E>{})), E>`を得る操作です．

```cpp
divide(3, 2).then([](expected<double>&& t){
  if(t) return int{*t};
  else return 0;
}); //expected<int>{1};
divide(3, 0).then([](expected<double>&& t){
  if(t) return int{*t};
  else return make_unexpected(t.error());
}); //expected<int>{unexpected_type<>{std::domain_error("divide by zero")}};
```
### **`catch_error(F)`メンバ関数**
　`catch_error(F)`メンバ関数は関数`f`を受け取り，中身が正常値であればそれを持った新たな`expected`を，中身が不正値であれば`f(error())`を返します．上の3つとは異なり型を変換することは出来ません(`expected<T, E>`から`expected<T, E>`を得る操作です)．

```cpp
divide(3, 2).catch_error([](std::exception_ptr e){
  try{
    std::rethrow_exception(e);
  }catch(std::exception& e){
    std::cout << e.what() << std::endl;
  }
  return 0.;
}); //expected<double>{1.5};
divide(3, 0).catch_error([](std::exception_ptr e){
  try{
    std::rethrow_exception(e);
  }catch(std::exception& e){
    std::cout << e.what() << std::endl; //divide by zero
  }
  return 0.;
}); //expected<double>{0.};
```
```
divide by zero
```

### **適用してみる**
　以上4つのメンバ関数の中から，今回は`then`と`bind`と`map`を使うことで，以下のようにスッキリ書けます．

```cpp
expected<std::string::size_type, const char*> func(double t){
  return divide(3, t).then([](auto&& d)->expected<double, const char*>{
                        if(d)
                          return *d;
                        else
                          return make_unexpected("divide by zero");
                     })
                     .bind(to_str)
                     .map([](auto&& s){return s.size();});
}
```

順を追って見てみましょう．まず，`divide(3, t)`の値を得ます．次に，`then`で`divide(3, t)`の結果によって処理を分岐しています．`divide(3, t)`が正常値ならそれをそのまま返し，不正値なら`"divide by zero"`を不正値として返します．これにより，`expected<double, const char*>`型のオブジェクトとなります．
　続いて，この`expected<double, const char*>`型のオブジェクトに対して`bind(to_str)`を呼び出しています．これにより，オブジェクトの中身の`double`型の値を`to_str(double)`に渡した結果が返ってきます．そして，最後に`map([](auto&& s){return s.size();})`を呼び出しています．これで，`to_str`の結果が正常値であればその文字列の長さが，不正値であればそれ(`"failed"`)がそのまま返ってくることになります．

## **その他**
- コピー・ムーヴ初期化/代入，`swap()`，比較などは正しく中身を見て処理してくれます．
- 有効なら値を取り出し，そうでなければ引数で渡したデフォルト値を返す`value_or(T)`などもあります．
- `expected`がネスト(`expected<expected<T, E>, E>`)した時，有効なら中の`expected<T, E>`を取り出し，無効なら外側の不正値を返す`unwrap()`というメンバ関数もあります．

# **応用 : 既存APIへの適用**
　さて，単にエラーハンドリングが出来るライブラリが存在するだけではレガシー言語を脱することは出来ないそうなので[^non-null-safety_is_legacy]，この`expected`を実際にWinAPIに適用していきたいと思います．
## **その前に**
　今回~~盛大に遅刻しながら~~実際にWinAPIに`expected`を適用していったのですが，**メチャクチャ不都合が出まくりました**．例えば，`expected`で使える型には結構制約があったり，他にも先程の「**適用してみる**」のようなエラー値の型を変換したいときにちょっと冗長だったりして元のだと段々不満になってきたので，今回`expected`を作り直しました．というわけで，差異を以下にまとめます．

- `emap`メンバ関数の実装
  - `map(F)`メンバ関数は`E`型の値を受け取る関数`f`を受け取り，中身が正常値なら`value()`の結果を，中身が不正値なら`f(error())`を不正値として返します．
  - `expected<T, E>`から`expected<T, decltype(f(error()))>`を得る操作です．
  - これにより，「**適用してみる**」のコードが以下のようになります．よりスッキリとしましたね．

```cpp
expected<std::string::size_type, const char*> func(double t){
  return divide(3, t).emap([](auto&&){return make_unexpected("dvide by zero");})
                     .bind(to_str)
                     .map([](auto&& s){return s.size();});
}
```
- `make_unexpected<E>(values...)`の実装
  - in-placeにエラー型を作れます．
- 多重入れ子になった`expected<expected<...<expected<T, E>, ...>, E>, E>`から再帰的に中の`expected<T, E>`を取り出す`unwrap_all`メンバ関数を実装
  - 正直使う機会がない方がいいと思います…
- `operator+`，`operator++`，`operator--`の実装
  - 元々のExpectedの設計[^member_function_and_operator_design]はC++的には正しいと思うのですが，一方でいちいち`value()`って打つのがメチャクチャ面倒だったのでチェック付きメンバアクセスが出来る演算子を勝手に生やしました．
  - `operator++`と`operator--`は共に後置です．
  - `operator+`と`operator++`が`value()`と同様，`operator--`がチェックして正常値のアドレスを返すという挙動になります．
- `has_error()`，`error_or()`メンバ関数の実装
  - 元々のExpectedだとExpected algorithmとして外部関数で実装されていたものをメンバ関数に取り入れた形
- `map`などのメンバ関数に渡した関数`f`で例外が発生した際，エラー型`E`によっては例外をキャッチするように
  - これも元々のExpectedで事前にマクロを定義しておけば使える機能ではあったのですが，`E`が`std::exception`で構築できる型に制約される[^error_traits]という大問題があったので，`E`によって例外をキャッチする実装としない実装に振り分けるようにしました．
- `do_()`関数を追加
  - Haskellの`do`構文みたいな感じで，中で`expected`を展開した際不正値であればそこで処理を中断してその値を返す関数[^do]です．
- `expected<T&, E>`を受け付けるように
- `noexcept`を書いた
- 1ファイル化
- Boost依存を排除
  - 逆に言えば`boost::exception_ptr`などのBoostの機能との親和性は損なわれているのでその辺は必要に応じてコードを追加しないとダメです．

以上改造済みの`expected`の実装が[こちら](https://github.com/wx257osn2/will/blob/master/_expected.hpp)です．

[^do]: 正確には「発生した例外を不正値として外に返す」関数です．チェック付きのアクセスに失敗した際例外送出されることを利用しています．
[^member_function_and_operator_design]: `operator*`でチェック無しのアクセス，`value()`メンバ関数でチェックありのアクセス，という設計．`std::vector`の`operator[]`と`at()`メンバ関数みたいに，「演算子は速度優先，安全寄りに倒したやつはメンバ関数で提供」って考え方がある**気がする**[要出典]．
[^error_traits]: 実際には`error_traits`の`make_error_from_current_exception`内で`make_error`の部分が通るかどうか，というのが問題なので，`error_traits<std::string>`をちゃんと作って，`make_error`で`e.what()`を使って構築する，といった実装を書けば`std::exception`から構築できない型でも例外を捕まえる実装で動作しますし，(あまりよろしくはないですが)例外を握りつぶす実装を書けばどんな型でも動くことは動きます．ただ，そんな`error_traits`をライブラリ側で提供するかと言われれば当然しません．

## **WinAPIに`expected`を適用してみた**
　　い　　つ　　も　　の
> [wx257osn2/will: WinAPI Wrapper Library](https://github.com/wx257osn2/will)
> https://github.com/wx257osn2/will

　willはインクルードパスの通ってるディレクトリにcloneした瞬間即使える，ヘッダオンリーのWinAPIラッパーライブラリです．
　これまでwillではエラー処理はガン無視・エラー情報を握りつぶしてnullptrを返すなど，結構ムチャクチャやってきてましたが，今回**全ライブラリのエラー処理に`expected`を使用する**実装に転換しました[^RIP_VS2015]．これにより，柔軟なエラーハンドリング[^tousha_rate]が可能になりました．

[^RIP_VS2015]: これにより対応コンパイラがVS2017RC以降となりました．やったぜ．
[^tousha_rate]: 当社比  可能にはなりましたが，もちろんエラーハンドリングをしない，という選択肢もとれます(その辺はユーザーに委ねられる)．

### **サンプルコード**
　以下がwillを使って適当に画像をボカシかけて描画したり音声ファイルを再生[^do_not_play_sound_on_ui_thread]したりするサンプルです．

```cpp
#include<will/window.hpp>
#include<will/graphics.hpp>
#include<will/audio.hpp>
#include<will/dwm.hpp>
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR pCmdLine, int showCmd){return *will::do_([&]{
	auto _ =+ will::com_apartment::initialize(will::com_apartment::thread::multi);
	auto wc =+ will::window::class_::register_(
		will::window_class::property()
			.background(CreateSolidBrush(0))
			.class_name(_T("D2DTest"))
			.instance_handle(hInst)
			.style(CS_HREDRAW | CS_VREDRAW));
	auto w =+ wc.create_window(
		will::window::property()
			.title(_T("D2DTest"))
			.style(WS_OVERLAPPEDWINDOW)
			.x(0).y(0)
			.w(640)
			.h(480));
	will::blur_behind{}.enable()(w.get_hwnd());
	auto d2ddevcont = will::hwnd_render_target::create(w);
	auto bitmap = will::do_<will::hresult_error>([&]{
		auto wic = +will::wic::create_factory();
		return d2ddevcont--->create_bitmap(+wic.create_converter(L"test.png")).value();
	});
	auto effect = will::do_<will::hresult_error>([&]{return d2ddevcont--->create_effect(CLSID_D2D1GaussianBlur);}).value();
	auto effect2 = will::do_<will::hresult_error>([&]{
		const auto fs = will::two_dim::attribute<will::two_dim::wh<float>>(bitmap--->get_dip_size());
		return d2ddevcont++.create_effect(CLSID_D2D1Scale)
		++.set(D2D1_SCALE_PROP_CENTER_POINT, D2D1::Vector2F(0, 0))
		++.set(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(640.f/fs.w, 480.f/fs.h))
		++;
	});
	if(bitmap && effect && effect2)
		*effect2 |= *effect |= *bitmap;
	auto format = will::do_<will::hresult_error>([&]{return d2ddevcont--->create_format(will::dwrite::format::property().name(L"メイリオ").size(30.F)).value();});
	auto brush = will::do_<will::hresult_error>([&]{return +d2ddevcont++.create_solid_color_brush(D2D1::ColorF(D2D1::ColorF::WhiteSmoke));});
	const std::wstring str = L"test";
	auto audio = will::media_foundation::startup().bind([&](auto&& mf){return will::audio::create(std::move(mf));});
	audio.map([](auto&& a){a.set_volume(.5f);});
	auto source = audio.bind([](auto&& a){return a.read_audio_file(L"test.m4a");});
	will::audio::source::buffer<2> sound_buffer;
	int t = 0;
	w.messenger[WM_ERASEBKGND] = [](auto&&, auto&&, auto&&)->LRESULT{return 0;};
	w.show();
	while(true){
		auto now = std::chrono::steady_clock::now();
		source.map([&](auto&& s){
			using namespace std::chrono_literals;
			s.play(sound_buffer, 5500ms);
		});
		t += 10;
		will::do_<will::hresult_error>([&]{effect++(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION) = 5 * std::sin(t * 3.14f / 180) + 5.f;});
		d2ddevcont.bind([&](auto&& dc){return dc.draw([&](auto&& x){
			x.clear(D2D1::ColorF(0, 0.f));
			if(effect2)
				x.image(*effect2);
			x.text(str, +format, D2D1::RectF(20, 20, 300, 100), +brush);
		}).map([&]{
			DwmFlush();
		});});
		const auto ret = w.message_loop(now, 60);
		if(!ret)
			return ret.get();
	}
}).catch_exception<std::exception>([&](std::exception& e){
	::MessageBoxA(nullptr, e.what(), "exception", MB_OK);
	return 1;
});}
```
今回は`test.png`と`test.m4a`を読み込んで利用するプログラムとなっています．そしてこのプログラム，**メディアファイルがなければそれに関わる処理だけ飛ばして他の処理は実行します．**例えば，`test.png`はあるけど`test.m4a`は無い，みたいな時に音声は再生しないけど画像の描画だけはする，という挙動になります．流石に

- COMの初期化に失敗する
- ウィンドウクラス・メインウィンドウの生成に失敗する

の2つはその場でプログラムを終了しますが，何故失敗したのかの原因は表示してくれます．

[^do_not_play_sound_on_ui_thread]: UIスレッドで音声周りを弄るのは一般にオススメされないので良い子のみんなはちゃんとサウンドスレッドを別に立ててそっちで弄ろうな！おっさんとの約束だぞ！  サンプルコードなので許して欲しい

### **エラーハンドリングの方法**
　上のプログラムで使っている，エラーハンドリングを適切に行いながらプログラムを記述するための方法を紹介します．`expected`を用いて提供されたAPIを使うときは，大体こんな感じになります．
#### **`if`チェックと`operator*`**
　上のコードだと`effect`周りでちょっとだけ使ってます．無難ですが，処理内容が`if`のスコープから外に出られないので当然**値の生成には使えません**[^no_reality]．副作用のみを期待する処理に対して使うことになります．

[^no_reality]: リソースを生成して，それを束縛する変数を`if`のスコープに閉じ込めるとその後ろで使えないよね，というお話．その値を使うコードと使わないコードを両方書いてifで分岐すれば一応出来ますが，組合せ爆発するので考慮しないものとします．

#### **チェック付き値取り出し**
　`value()`メンバ関数を呼ぶやつです．或いは，`operator+`や`operator++`，`operator--`[^suffix_decrement]も同類です．今回のコードは主に演算子の方でやってます．こいつ単品ではエラーハンドリングはされないので，`try`-`catch`とか`do_()`とかを使って外でエラーハンドリングをする必要があります．

[^suffix_decrement]: え？どこにも`operator--`が見当たらない？ `--->`の前半分です．

#### **`map`と`bind`**
　上のコードだと音声周りで使っています．単一の`expected`から値を取り出して処理する分には，中身(メンバ関数に渡す関数)は非常に素直に書き下せる，速度的にそこまで大きなオーバーヘッドがない，の2点が利点です．一方で，内部で発生したエラーを正しく外まで伝播させたい，複数の`expected`から値を取り出して処理したい，といった際に**メチャクチャネストします**[^deep_nest]．あと，個人的には`map`と`bind`をよく間違えるのでつらいです．

[^deep_nest]: 今回だと，`effect2`の生成部分を`bind`で書いたりするとそこそこネストします．また，willの実装では(オーバーヘッドを減らすために)主にこの手法を多用したため，**8段`bind`+1`map`みたいな地獄が発生してます**(逆に言えば，ライブラリでそこまでやってるのでユーザーコードではそこまで出てこないでも済んでいるわけです)．

#### **`do_()`**
　今回新たに加えた関数`do_()`を使ったもので，上のコードだと主に画像周りで使用しています．`do_()`の中ではチェック付き値取り出しを好きなだけ行える[^perfect_error_handling]ので，特に複数のリソースや処理を扱いつつ不正値を外部に伝播する場合，中身は`expected`の値に片っ端から`+`を付けていくだけであとはそのまま書き下せるのでかなり楽に書いていけます．ただし，ハンドリングの実装が例外なので**失敗したときのコストが比較的重い**です．この辺は完全なシンタックスシュガーでは無いのでHaskellほど上手くはいきません…

[^perfect_error_handling]: チェックで不正値だった場合，その値を正しく外部に伝播させるためには`map`/`bind`だと副作用のみを期待する処理でも(不正値を外部に伝播するためだけに)ネストしていく必要がありましたが，`do_()`ならチェックさえかければ済む(チェックは`operator+`を適用するだけな)ので大分簡単になります．

## **`expected`のもたらす利便と限界**
　さて，willは便利なのですがこの記事の本題は`expected`．この節では実際にWinAPIに`expected`を適用した際に感じた`expected`のもたらす利便とその限界について見ていきます．
### **利便**
#### **統一されたインターフェース**
　記事冒頭で話した通り，世の中にはエラー情報の扱い方がいくつもあります．WinAPIでは`GetLastError()`と`HRESULT`が主に使われますが，API毎に異なるエラー情報を正しくハンドリングするのは非常に面倒ですし統一性に欠けます．その点，`expected`を用いることで統一的なインターフェースを提供でき，多くのエラー処理が同じように記述することが出来ます．また，APIによっては`GetLastError()`ではエラー情報が得られないものなどもあります．この差も`expected`を使えばドキュメントの注釈ではなく，型レベルで示す事ができます．
#### **関数のインターフェースが綺麗になる**
　エラー値を返すために外部変数に書き込みにいったり，逆に処理の成功・失敗を戻り値にしてしまうがために処理の対象は参照やアドレスで引数から受けたり，といった実装上の都合からくる関数のインターフェースを汚くする問題を解消してくれるので，引数で入力をとり，戻り値で出力を返す，という基本的で本質的なインターフェースを維持できるようになります．
#### **null安全**
　チェック付き値取り出しなどを使えば得られた値がヌルでないという保証が得られるので，null安全です[^true_null_safety]．

[^true_null_safety]: ここでいうnull安全とは，「null が原因で実行時エラーを起こさない性質のこと」です．

### **限界**
#### **RAIIと相性が悪い**
　リソースの初期化と解放を変数の生成と破棄に紐付けるRAII[^RAII]という考え方があり，C++では標準ライブラリでも多用されています．これは当然，コンストラクタで初期化処理・デストラクタで解放処理という流れになります．しかし，Expectedで値を返そうとするとどう足掻いても値を生成するためのヘルパ関数が必須になってしまいます[^but_not_so_bad]．
　また，解放処理はより深刻です．デストラクタは当然値は返せませんので，外部変数への書き込みを除けばエラーを伝播する唯一の方法は例外送出となります．しかし，C++ではデストラクタで例外送出するのはタブーとなっています[^RAII]．そのため，解放処理をメンバ関数で別に実装してそちらを呼び出してもらう，或いは解放処理の際のエラーは破棄してRAII，という形にせざるを得ません．当然解放済みか否かを判断するためのフラグが必要になることもあります[^but_not_so_bad2]．

[^RAII]: 詳しくは[こちら](http://qiita.com/wx257osn2/items/e2e3bcbfdd8bd02872aa)
[^but_not_so_bad]: 勿論，エラーハンドリングを適切に行わずnull安全性を担保できない状況よりはマシですし，コンストラクタからExpectedを返す関数を呼び出してチェック付き値取り出しで中身を取り出せば一応コンストラクタからの初期化も可能です．
[^but_not_so_bad2]: こちらも，解放処理をデストラクタで呼び出して結果を無視すればデストラクタで例外を投げずに破棄できるようになるので実装する際そこまで重くはないですし，実際には標準ライブラリも概ね同様の方針(解放処理をメンバで呼び出して事前にエラーハンドリング込みの解放できる形式)で設計されているのですが…感覚的にちょっとね…　/　そもそも，解放処理で発生したエラーに対しての対応なんてログを出力するぐらいしか出来ないだろ，という話もある

#### **速度と構文を両立できない**
　上の「**エラーハンドリングの方法**」でも出てきましたが，言語側からの支援無しには実行速度と構文の書きやすさを両立するのは難しいですね…この辺は`expected`の限界というよりC++の限界かもしれません．

#### **デバッガが使いにくくなる**
　`operator+`や`bind`など(特に後者，ネストしてると最悪)を使うと，デバッガでステップ実行する時にステップインすれば見知らぬライブラリのコードに飛ばされ，ステップオーバーすれば(特に後者は渡してる関数の)中身の処理をまるっと飛ばし，という感じでまともな使用感ではなくなります．カーソル位置がどの処理を指しているのか，ステップオーバーしていい処理とステップインすべき処理の差異を判別でき，ちまちまステップインしていかないと従前の平たいコードのようにはデバッグできないことになります．

# **まとめ**
- C++で綺麗にエラーハンドリングをするためのExpectedというライブラリがある
- 汎用性も高く非常に便利
- C++でやっていくにはどうしても厳しい面も無いことはない

## **謝辞**
　Media Foundationのサンプル実装を提供してくれた[Azaika](https://twitter.com/azaika_)くん，ありがとうございます．ちゃんとwillに載せました．
　`Either`モナドや関数型プログラミング言語に関する質問，API設計に関する相談に乗ってくれた[phi](https://twitter.com/phi16_)くん，ありがとうございました．この手の話はやっぱりHaskellマンに聞くと経験が豊富なので非常に助かりました．

## **謝罪**
　11日オーバーです！！！！！！！！！！！メチャクチャ遅れました！！！！！！！！本当にごめんなさい！！！！！！！！！！！！！！！

---

明日は~~natsu1211さんの『c++でLINQ実装してみた話』です．~~ ~~空いてるので誰か書こう．~~ [yohhoy](https://twitter.com/yohhoy)さんの『[XOR swap今昔物語: sequence pointからsequenced-beforeへの変遷](http://qiita.com/yohhoy/items/ab15739c99d3f8872407)』です．


---