関数型プログラミングは早く普及しそう

関数型言語は普及するのか?みたいな議論がtwitterで話題になっていたので、自分の意見を述べたくなりました。

こちらの記事で

Java はやっぱり C と似ているんです。つまり構造化言語を書いていたプログラマ達からオブジェクト指向言語はすぐ近くに見えていたんですよ。

っていうのは凄く同意できて、僕自身もScalaやLispを読むと思わず目が丸くなりモニタの前で10分ぐらい硬直してしまうのですが、

この似ているのがとても厄介で、似ているがゆえに「オブジェクト指向言語で、オブジェクト指向でないコード」を散々見てきました。

例えばこんなコードです。

//荷物の大きさから送料を込みの値段を計算。
height = product.getHeight();
width = product.getWidth();
depth = product.getDepth();

//高さ・幅・奥行きどれかが1m以上であれば送料\1000
shippingCharge = 500;
if (hegiht > 100 || width > 100 || depth > 100) {
shippingCharge = 1000;
} else if (...) {
//省略
}
//商品の値段+送料
totalPrice = product.getPrice() + shippingCharge;

※1

オブジェクト指向が理解できている人であれば、上記のコードを見た瞬間に

totalPrice = product.getPriceWithShippingCharge();

みたいにリファクタリングしたくなりますよね。

でも、実際の現場ではリファクタリング前の「なんちゃってオブジェクト指向」の様なコードが本当に多い。※2
僕の経験値で言えば、経験3年ぐらいのPGの5人のうち4人は「なんちゃって」のコードしか書けてない。
経験5年以上の概要設計やマネジメントを任されてる人でさえ「なんちゃって」のコードを読んでもなんとも思わない人が多い。

なんで「なんちゃって」が問題にならないのかと言えば、
「オブジェクト指向でなくても機能要件を満たすことが出来る。」
からです。
リファクタリング前のコードは将来拡張性・保守性の懸念(別の送料計算方式の商品が来たら条件分岐どうするの)はあるのですが、
「送料込みの商品の値段を計算する」と言う、機能要件は満たしているのです。
逆に、リファクタリング後のコードは拡張性をポリモーフィズムでカバーできるので長い目で見たら優れているのですが、
それは「送料込みの商品の値段を計算する」要件とは何も関係ないのですね。

要するに

  • 構造化プログラミングは、それを覚えないと仕事にならないので絶対覚える
  • オブジェクト指向プログラミングは、それがなくても仕事になるので積極的に覚えない

だから、オブジェクト指向プログラミングはあまり普及してないというのが実感です。

同様の問題は関数型言語にも起こりえます。

下記の様な関数型言語らしくないコードも(Scala)※3

while(i < aList.length){
aList(i) += 1
}

上記をリファクタリングした関数型言語らしい書き方も(Scala)※3

var f = (x:Int) => x + 1
map(aList)(f)

どちらも機能要件(配列の要素に1をプラスする。)は満たしているのですよね。

だから、オブジェクト指向と一緒で
「関数型言語の普及より、関数プログラミングの普及は遅れる」と予想しています。

でも、「オブジェクト指向」よりは、「関数型プログラミング」の方が普及のスピードは早いと思います。
「非オブジェクト指向」における、「保守性」「拡張性」の問題は
「人員の投入」「プログラマに『頑張って』もらう」など、デベロッパ側に負担を押し付けるだけで何とかなるのですが、
「非関数型プログラミング」における、「マルチスレッド環境でのトラブル」「並列環境でのパフォーマンス問題」は
ソフトウェア利用者に「品質」として露見するので、深刻度が高いからです。

※1、「送料って住所で決まるんじゃないの」ってツッコミはご容赦お願いします。
※2、JavaやRubyのような「最初からOO言語」よりもPHP・Perlのような「後付OO言語」の開発者のほうが「なんちゃって」が多い気がします。
※3、ちょっと「非関数型」と「関数型」の例に自身がないです。もっと良い例があれば教えて下さい。

javascriptの論理演算子

今日は、javascriptの論理演算子について話します。
と、言うのも僕が普段使ってるPHP/Javaとjavascriptは論理演算子の返す値が違うのですね。

Mozillaのjavascriptのドキュメント(論理積)には次のように書かれています。

(Logical AND) Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.

要するに、expr1 && expr2 の時
expr1がfalsy(false判定)であればそれを返して、そうでなければexpr2を返すそうです。

PHPやJavaと違ってboolean値でないのがポイントで、
例えば

if(a){
 return a.method();
}else{
 return a;
}

は以下のように省略できます。

return a && a.method();

そしてjavascriptの論理和は以下のように説明されています。

(Logical OR) Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true; if both are false, returns false.

つまり、expr1 || expr2 の時
expr1がtruthy(true判定)であればそれを返して、そうでなければexpr2を返すそうです。
(&&の逆です。)

だからjavascriptでは以下のように変数を初期化することができます。

var myVar = input || default;

さらにテクニカルな使い方はこのサイトで解説されています。
http://addyosmani.com/blog/exploring-javascripts-logical-or-operator/
これRubyユーザであればa &&= b や a ||= b があるのですぐになじむかも知れませんが、
PHP使い/Java使いだと、混乱しそうですよね。