読者です 読者をやめる 読者になる 読者になる

セカイノカタチ

世界のカタチを探求するブログ。関数型言語に興味があり、HaskellやScalaを勉強中。最近はカメラの話題も多め

マーブルワーズ

オブジェクト指向と関数型で副作用の扱いが違うって知ってた?

Haskell Scala プログラミング 関数型 オブジェクト指向

最近、オブジェクト指向と関数型を比べる人が多くなってきたみたいなんで、自分の考えをまとめてみます。

まず、本件ですが、壮大なテーマだと思いますので、全体を網羅して書くのは難しいです。

なので、主眼を絞ります。

主眼は、ズバリ「副作用」です。

副作用とは、薬なんかだとその薬が目的とする「作用」に付随してくる好ましくない「作用」の事を指しますよね。

例えば、風邪薬を飲むと「眠くなる」とか、タミフルを飲むと「ベランダから飛び降りたくなる」*1とかです。

プログラミングに於いては、関数の戻り値を「作用」として、それ以外の作用を(良し悪し関係なく)「副作用」といいます*2

副作用によって、プログラム全体の動作が複雑になり、わかりにくくなるため、最近のプログラマー達の議論では「悪」であるということでコンセンサスが取れているようです。

関数型言語と副作用の戦い

関数型言語における、対副作用兵器は「参照透明性」です。

関数から、副作用そのものを排除してしまおうという発想で、変数は定義と同時に値が確定し、その後変更できませんし、関数も戻り値以外にプログラム内部の状態を変更できません。

このため、関数は同じ引数ならば必ず同じ結果を返すことが保証され、副作用の心配から根本的に開放されます(やった!)。

ここまでの(過激な)機能が備わっていない言語でも、なるべく副作用がないプログラムを書こう!というのが関数型プログラマーの戦闘スタイルです。

しかし、完全に副作用がないプログラムと言うのは実現できません。なぜならば、全く変化のないプログラムは現実世界の我々にとって役に立たないからです。

そのために実際は副作用の発生する領域と、副作用の無い純粋な領域を分離して使います。

詳しくは、下記の記事で書きました。

プログラムを純粋に書けって言われたけど、どこまで純粋に書けばいいの? - セカイノカタチ

  • 副作用の無い世界とある世界を完全に分離する
  • そして、副作用がない世界をなるべく多く確保し、副作用がある領域は慎重に管理する

これが、関数型言語生存戦略です。

オブジェクト指向言語と副作用の戦い

「副作用」という発想自体が、関数型方面発祥なため(ですよね?)、オブジェクト指向プログラミングでは、「副作用は野放し」と思われてる方も多いかと思いますが、違います。

オブジェクト指向言語における、対副作用兵器は「カプセル化」です。

森羅万象、あらゆるものをオブジェクトとして捉え、クラスを定義しインスタンス化していく事で現実世界をコンピュータの中に再現する。

これがオブジェクト指向プログラマーの戦闘スタイルですが、インスタンスというのは副作用をパッケージしたものです。

逆に言うと、副作用が無いのであればインスタンスの存在価値は希薄になります。

自分は、HaskellScalaというコードの移植を(趣味で)よくやるのですが、ほとんどインスタンスが必要ないコードになります。

あっても単純にデータ構造を表すことになるので、クラスである必要がないです。Cで言うところの構造体みたいなもので十分ということになります*3

オブジェクト指向インスタンスは、副作用を管理する箱です。

副作用というのは変化する値ですが、野放しにすると危険なので箱に入れて専用の関数経由でしか変更できなくします。

副作用同士が反応すると危険が増幅する性質があるため、箱はなるべく小さく設計し、箱同士のメッセージ交換によって動作するようにします。

これが、オブジェクト指向言語生存戦略です。

まとめると

関数型とオブジェクト指向で、「副作用」に対するアプローチは180度違います。

関数型は副作用を「外的なもの」として扱い、main関数(つまり外界)から繋がったエリアの内、副作用を必要とする領域を隔離する事で安全性を保とうとします。

対して、オブジェクト指向では、副作用をなるべく小さい単位で「内側に封入」しようとします。

この態度の違いは本質的で、コーディングテクニックがどうこうという問題では無いと思います。

なんで、両者の食い合せは悪いのかな。と思っています。

また、両者とも違ったアプローチを取りながらも同じ目的に向かっているため、優劣の問題ではないです。

両方共、得意不得意があって完璧ではないんで、住み分けたり使い分けたりする必要があるし、お互いの良い所は可能な限り取り込んで、より良いパラダイムを作っていったらいいんじゃないかと思います。

結論「みんな仲良く」

仲良く喧嘩しな。ということで、やっぱりトムとジェリーは偉大だった*4

おしまい。

*1:本当かどうか知りません

*2:少なくともここではそういうことにしておきます

*3:実際は代数的データ型を表すのに継承とかが欲しい。けど副作用の話とは関係ないので割愛

*4:わからない人は周りの年寄りに聞こう