...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

C++ と Structural Polymorphism と型推論

Xpressive の力は Structural Polymorphism の力

果ては Xpressive みたいな、正規表現を文字列以外の方法で記述できる実装だと、「文字」の「列」ですらなくても「文字とおなじようにふるまうもの」の「列」に対して正規表現使えちゃったりとか。intの配列から、100未満の値が繰り返されてる部分を取り出し!

d.y.d.

おら Xpressive のこと誤解してただ!


C++ 的には正規表現を抽象化するとそうなるのか.
そうか,そうなるんだな.
なんてこったい.

制約と誓約の過不足

そもそも STLC++標準の、データ構造&アルゴリズムのライブラリ)が徹底して「あれとこれとそのメソッドを持ってるオブジェクト全てが処理対象です」という形式で機能を提供しているのが始まりだと思うんですが、正規表現に限らず、あらゆる(というと言い過ぎですが) C++ のライブラリはこんな方向でできています。例えば asio (ネットワークI/O) のドキュメントなんかが、ちゃんとハイパーリンクされてて一番わかりやすいかも。引数 SyncReadStream や MutableBufferSequence をクリックしてみるとわかるように、「○○の派生クラスのインスタンスを引数として受け取ります」みたいなAPIではなく、「read_someメソッドを提供しているオブジェクトならなんでも引数として受け取ります」という定義になっています。そういうふうにできている。

d.y.d.

STL 以降の C++ てのは compile-time に duck typing をやりたいんだと.
そのために型による制約/誓約の能力を使うよと.
そんな感じ.


ただまあ,これから書くことはC++に限ったことじゃないけど,大抵,ライブラリの要求を満たした型を自前で用意するのってめんどくさいんですよね.
十分な説明がなかったりして,結局,既存の実装を見ないと書けなかったりする.
そういう風に感じるのは,多分,ライブラリの要求が高級すぎることがよくあるからなのかな.


実際,std::basic_iostream を継承して自前のストリームクラスを作ろうと思ったらどんだけーなことになるし,そりゃまあ自由度は低くなるかもしれないけどiostream の要求はこれくらいでよくね?って声が boost::iostreams という形になってるわけだし.


ねえ,そのライブラリが要求する特性は本当に過不足なく「それ」ですか?
本当にその特性を持った型を「わたし」が書かないといけないのですか?
その要求が妥当なものだったとしても,「それ」を満たした型を書くために必要な情報は「コード以外の形で」「わたし」に提供されていますか?
本当は「わたし」が努力して調べるのが真っ当なんだけど,やりたいことに比べて,特性/セマンティクスを満たした型を用意するために過剰な努力/労力が必要ではないですか?
とか,とか.

読み書きの違い

これは単純にポリモーフィズムのお話で、静的型付け というよりは、nominal subtyping が脳のリソースを大きく引っ張っていく割に、作りたいことの本質ではないから。動的型付OOPLとか OCaml のような、structural subtyping のほうが ぜんぜん Lightweight に感じます。

LLとOO - みねこあ

そして,

一方,いくら簡潔に記述できてプログラムが書きやすくなっても,型情報がなければ,プログラムを読解しにくくなるのではないか,という懸念もあります。書きやすくても読みにくければ仕方がありません。これに対しては,処理の本質に集中した簡潔なプログラムは,書きやすいだけでなく読みやすい傾向があると答えられます。実際,動的型の言語(例えばRuby)のプログラムと,静的型の言語(例えばJava)のプログラムを比べると,コード量で数倍の差があることも珍しくありません。多くの人は動的型の言語の方が読みやすいことが多い,と感じているようです。

まつもと直伝 プログラミングのオキテ 第4回(3) | 日経 xTECH(クロステック)

動的な duck typing の世界にいる方はこういうことをよく仰る.
なるほど,本質を記述することに集中できるから書きやすいらしい.
でも,「型情報がなければ,プログラムを読解しにくくなるのではないか,という懸念」に対して,「プログラムの読解性が本質の記述に集中しているかどうかにかかっている」というのは,本当なのかな?
静的な duck typing であれ,動的な duck typing であれ,duck typing を多用したコードは読みにくくて,めんどくさかった経験がある.
じゃあ,あのめんどくささは一体なんなのか.


以前,言語についての知識がほとんど無い状態で duck typing 使いまくりの世界でプログラミングしたときには(←そういうことをするのが間違ってる),ありとあらゆる状況で duck typing を要求されるせいで,どの関数がどのようなオブジェクトを返すのかがユーザコードの側にははっきりと現れていなくて困惑した.
その関数が何のオブジェクトを返したのかをコード上から知ろうとすると(←リファレンス嫁),そのオブジェクトが別の場所でどのように使われているかを読んで,アタリを付けないといけなかったからだ.
何のオブジェクトかではなく,どんな特性を持っているオブジェクトなのかを知ることは比較的容易だ.
ただし,そのオブジェクトを使っているコードが近くにありさえすればだ.
また,オブジェクトがわかるわけではないから,特性Aを持っているからといって特性Bを持っていることは保証されない.
もしそのオブジェクトが何なのかを早々に知ることができたら,どんな特性たちを持っているかがすぐにわかって,コードを読む大きな手がかりになるはずなのに.


つまり,duck typing を多用したコードを僕が読み書きしたときに感じためんどくささは,きっと,C# 3.0 における型推論の是非論において何度も説明されたのと同じ問題によるものなんだろうね.


以上,初投稿から何度かの修正を経て,これにて完成とします.