Option型とかMaybeがなんなのかの説明は、今更必要ないだろうから省く。
ググればいくらでも出てくる。
今現在、大抵の言語は上記に相当する機能を持っている。
Haskellについてはいうまでもあるまい。ScalaやHaxeは組み込みでOption型を実装している。Groovyには?.
という演算子がある。
Rubyについては、ActiveSupportというRails付属の便利ライブラリでObject#try
というものを提供している。
Pythonには標準ではOptionなどにあたる仕組みはない。
また、Rails的存在にあたるDjangoについても、例えばModel.objects.get()の結果が「該当なし」あるいは「複数」である場合、普通に例外が発生する。プログラマーは責任を持ってそれをcatchせねばならない。
There's Only One Way To Do It
「全てを明示的に」というのはPythonの基本哲学である。素晴らしい哲学だし、だからこそ僕はPythonを気に入っているわけだ。Option型を使うことについてのPythoniacな解答は恐らく「失敗したなら例外を出せ」なのだろう。あるいは"There's Only One Way To Do It."を引き合いに出すかもしれない。
しかし僕は、この程度の動作にすらErrorを用いることについては些かの疑問を抱かずにはいられない。
例えばだ、'DBにコネクトしようとして通信の障害により失敗する' というようなケースについて例外を用いるのは適切だと思う。まさしく例外的な状況だからだ。
だがしかし、'あるレコードからユニークな値をとってこようと思ったら空だった' というような状況を、果たして例外的だと呼んでよいのか。
例外と失敗が区別すべき物であるならば、それに対処する方法もまた分かれているべきではないかと筆者はおもう。
例えば、dictionaryへの存在しないkeyでのアクセスが例外を発生させるのと、Nothing型のオブジェクトを返すのはどちらが安全でわかりやすい(そしてスマートな)挙動だろうか? 無論、単にnullやundefinedを返すなんてのが論外であるのは言うまでもないが。
言語側でJavaのようなチェック例外の機構を備えていればそれも良いだろうが、Pythonはそうではない。もしそのような仕組みを備えていたとしても、Python的簡潔さとはかけ離れた書き味になるであろうことは想像に難くない。
Object#tryもどき
from operator import methodcaller class Perhaps(object): def __init__(self, var): self.var = var def try_(self, methodname, *args, **kw): v = self.var if v is None: return self else: self.var = methodcaller(methodname, *args, **kw)(v) return self
色々と足りていないが、とりあえずもどきっぽいものを実装してみた。
Pythonは組み込み型を勝手に拡張することは出来ないので、ラップするような形になる。
上記の型を返すようにすれば、
>>> Employee.object.get(id=1).try_('title') 'Hachibee'
みたいな書き方が出来るようになる。
その上で、真に例外的である状況や、特に取り扱いに気をつける必要があるものについてはexceptionを使うようにすれば、結果的に明示的でわかりやすいコードになるのではないかと思う。
原因を返したい場合はEitherを使う手もある。 少し長いので https://gist.github.com/hachibeeDI/532820a6d84bc5eb0d2d にあげておいた。こちらも色々と最低限な感じだが。
こちらはモナドを意識した実装になっていて、ある程度以上、コードの見た目を変えてしまう。
しかし、こいつを導入したところで致命的にソースコードの可読性や保守性を落とすようなことがありえるだろうか? Noneを返す関数とどちらが扱いやすい?
まとめ
アカデミックをこじらせた関数型ジャンキーの語る「シンプル」はイマイチ好きになれないけど、Pythonの書き方も少しづつ変化していっても良いのではないかな。
pathlibが3.4で標準ライブラリに入って、結構避難を浴びたりもしているようだけども僕は好ましい変化だと思っている。
デザインのトレンドが、スキューモーフィズムからよりミニマルなフラットに移り変わっていくように、コーディングスタイルにおけるシンプルの定義もまた変化していくべきなのだろう。
「知らない人が読めない」なんて言い出したら、リスト内包もなんも使えなくなるよ。あんた最初っからreduceの挙動わかったんかいなーみたいなー。
やりすぎるとただのクソコードになるけど、ある程度のラインで足切りしていかないとそれはそれでクソコードが生まれる。そこのバランス感覚はエンジニアにとってのコミュ力だ。
つーかOption型いいじゃん、わかりやすいじゃん。こんなん使った程度でガタガタいうなし。
とまで書いたけど、もしかしたらPythonでここら辺を全面採用してるもんが、僕が知らないだけで結構あったりしたらウケるなって思いました。ビビり過ぎか?
おしまい。