【質問#56】Scala反対派に対するご意見

質問・悩み相談の回答です。

質問

『Scala反対派の意見を集約すると「Scalaはシンタックスが分かりにくすぎる。理解の困難さはC言語→Javaの比ではない」「Scalaはスタンダードにはならない。Javaの代替にはなりえない。数年後消えているエコシステムかもしれない」というあたりでした。この点に関しても色々思うところはあるのですが、省略。』

私もこの意見に同意する側です。
もしよろしければ反対派の意見に対して、どのようにお考えだったのかをブログに書いて頂けると嬉しいです。

回答

Scala使いがまともなJava開発環境を模索する(続き)という記事で書いた内容についてですね。

ご質問は下記

「Scalaはシンタックスが分かりにくすぎる。理解の困難さはC言語→Javaの比ではない」
「Scalaはスタンダードにはならない。Javaの代替にはなりえない。数年後消えているエコシステムかもしれない」

について「色々思うところがある」というのは具体的に何か、ということですので、まずそれを説明します。

シンタックスが分かりにくすぎる

こう思っている人は、Scalaという言語に多数の演算子や制御構文があり、それを全て理解するのが困難と思っているのではないでしょうか。

「多数の演算子や制御構文がある」は正です。Scalaは演算子や制御構文を独自に定義できるからです。しかし、それを理解するにはいくつかの単純なルールさえ覚えてしまえばそれで良いので、理解は最初に皆さんが受ける印象ほど大変なものではないと信じています。少ないルールを組み合わせることによって結果的に複雑なDSLを定義できてしまうという感じでしょうか。ちなみに、標準で提供している本当(?)の制御構文はif, for, while, matchくらいです。それ以外の制御構文や見たことも無いような独自のDSLは各種ライブラリが独自に定義したものです。

もし「ルール」にどんなものがあるかは下記が非常に分かりやすくまとまっているのでまずはこれを参照ください。

Scala の省略ルール早覚え

一つ例を示します。Play FrameworkではActionを以下のように定義します。

def index = Action {
  Ok("Hello!!")
}

これを見た初学者は、「Actionって何だよ…」「Okってなんだよ…」と面食らうでしょう(わたしはそうでした)。これはいくつかの省略ルールを使わずに書くとこういう感じになります。

def index():Action[AnyContent] = { 
  return Action.apply( () => {
    Ok.apply("Hello!!")
  })
}

まず、returnは省略できます。ブロックの最後のステートメントはreturnとして扱われるからです。

def index(): Action[AnyContent] = {
  Action.apply(Ok.apply("hello"))
}

次に、applyという名前のメソッドに限っては名前を省略できるというルールがある(インスタンス生成などに使いたいからです)ので、applyも省略できます。

def index(): Action[AnyContent] = {
  Action(Ok("hello"))
}

引数がなければ引数リストのカッコも省略できます。省略すると、呼び出し側のルールが少し変わるのですがここでは触れません。

def index: Action[AnyContent] = {
  Action(Ok("hello"))
}

戻り値の型も省略できます。「そこまで省略すると可読性が無くなるのでは」と思った方は明示的に型をつけてください。Scalaではどちらの書き方でも選べるのが良いところです。

def index = {
  Action(Ok("hello"))
}

ちなみに、Scalaで戻り値の型を省略するのが推奨されているわけではありません。特にpublicなスコープにある関数には型をつけていたほうが良いでしょう。ただ、Playのアクションに関して言えば戻り値の型が分かったところで何か嬉しいわけでもないですし、だいたい型はAction[AnyContent]になるので私は型を省略しています。

次に、関数がシングルステートメントで済む場合はコードブロックにする必要がありません。なので中括弧も省略できます。

def index = Action(Ok("hello"))

ただ、コントローラのアクションの定義が一行で済むことはあまりないでしょう。そういう時は以下のような書き方ができます。

def index = Action{
  val a = "hello"
  val b = a + "world"
  Ok(b)
}

Scalaでは最後の引数リスト(Scalaでは引数リストを複数取ることが出来ます)はコードブロックにして良いことになっています。

ちなみに、Action.applyのシグネチャは、

final def apply(block: ⇒ Result): Action[AnyContent]

のようになっています。「⇒」(=>と書いても良い)は何かというと、与えられた引数(コードブロック)は関数applyの中で必要になったときに評価されるという意味です。名前渡しとも言います。普通はapplyが呼ばれる前に引数を評価して値を取得しますね。

というわけで結果として

def index = Action {
  Ok("Hello!!")
}

のような書き方になります。ああ、説明し忘れましたがOkはHTTP 200を返すという意味で、その引数はResponse bodyになります。

「たかがHelloWorldでこんなに覚えなきゃならないのか…」とお思いでしょうか。確かにいきなり上記のルールをすべて覚えるのは大変ですが、しかし、上記を覚えてしまえばScalaの書き方の半分以上(←感覚的)はたぶん網羅してしまっていると思います。

重要なのは、

def index = Action {
  Ok("Hello!!")
}

のように、「必要な情報のみが書かれていて余計な文字が削ぎ落とされている」という書き方ができる(つまりDSL)というのもScalaの良いところです。いいや、俺はそういう書き方は気に食わないな。という場合は、前述したように両略せずに書くこともできます。その自由度があるというのが重要だと思ってます。

理解の困難さはC言語→Javaの比ではない

これは個人の感想だと思うので何とも言えないですが、私はオブジェクト指向を理解する(つまりC→Java)方がScalaを理解するよりも難しかったです。ただ何故かを端的に説明できないので、ただの感想です。

Scalaはスタンダードにはならない、Javaの代替にはなりえない

字面だけみるとそもそもスタンダードって何だよ、って感じですが、私にこれを言った人は、「スタンダード」という言葉を今のJavaの立ち位置という意味で使っていたと思います。ですから「スタンダードにはならない」「Javaの代替にはなりえない」というのは同じ意味だと考えます。

そして、「Javaの代替にはなりえない」というのはある種当たり前の話です。両者は方向性が違うからです。Scalaが目指したのはオブジェクト指向と関数型の融合で、Javaが目指したのは煩雑なメモリ管理からの解放、オブジェクト指向設計の提供、中間言語の導入によるマシン依存からの解放、標準APIで実用的な分散処理・マルチスレッド処理の提供というあたりではないでしょうか。

両者は似てはいますが、特に「関数型」の考えが導入されているか否か、という点において大きく違います。Java 8でも関数型な機能が増えたじゃないかと思われるかもしれませんが、immutable型がなかったり型推論がまだ弱かったりと色々不足している部分があります。Streamについても、あれは関数型プログラミングというよりは恐らく並列・分散処理を意識したものでしょう。だって「Stream」ですから。

というわけで、両者の方向性が違うので代替にはならないのは私は当然だと思います。

数年後消えているエコシステムかもしれない

未来の事は誰にも分からないのですが、私はScalaはずっと続いていく言語だと思います。

まず、何だかんだ言ってScalaは2003年から開発が始まり2004年に公開された言語ですでに10年以上の歴史があります。根本の設計がプアだったらそもそも今日に至るまでに消失していると思います。

そして現在ではScalaには十分なユーザー数があります。確かに比率で言えばまだ少ないですが、国内においてもScalaを用いたプロダクト開発はあちこちで行われています。何か疑問があった場合は、StackOverFlowあたりで検索すればすぐに回答が見つかる程度にはユーザー数が居ます。Scalaのフレームワークやライブラリもかなりの数が存在します。世界各地でScala MatsuriやScala Daysなどといったイベントが開催されています。

これだけ広まったら少なくとも今後数年のうちに消えてしまうとは私は思えないのですが、いかがでしょうか。

言語なんてどうでもいい

解答は以上の通りです。以下は質問とは関係なく、このブログで何度か書いたことですが、また改めて伝えたい事です。

まず、私は私の個人的な考えとして「言語なんてなんでもよくて、ビジネスを回していくことが重要」と考えています。いや、全ての言語が工学的応用を目指したものでは無くてアカデミックなものもあるでしょうが、しかし私はビジネスに興味があるので常にそう思っています。これは正しいとか皆がそう思うべきとかいうわけではなくて、私はそうだというだけです。

「皆で議論し合った結果、ScalaではなくてJavaを採用すべきとした」、それ自体は正しい事です。ScalaではなくてJavaを選択すべき理由は沢山あるでしょう。新しい技術を導入するリスクをどう評価するか、というだけの話です。Javaで稼ぎになるプロダクトを作っている会社は沢山あります。ビジネスを成功するのに技術的に優れていること(Scalaの事を言ってるわけではありません)が必須ではありません。

ですから、ビジネスを回すためにJavaが何らかの理由で必要だったというケースでは躊躇なくそれを選択すべきです。いや、そこまで行かなくても現在のメンバーのスキルセットがJava系中心で、Scalaに移行するメリットが無いと判断しているならばJavaを使うのが普通でしょう。

前述の記事中で、私が担当するプロジェクトにおいて議論の末にScalaの導入を見送ったときは私はすぐに引き下がりました。私の意見をゴリ押ししてもビジネスは回らないからです。

それでも私がことあるたびにScalaの導入を主張するのは、JavaよりもScalaを使った方が最終的に高品質なプロダクトを効率よく作れると信じているからです。そこに至るためには数々の壁があるでしょうが、それをペイできるメリットがあると信じています。

そして重要なのは、最終的に得られたメリットが私に対する組織内での評価向上や、私の仕事自体が楽になって早く帰れるという利益に結び付くことです(私は自己中なんです)。

だから、私は今後も私が担当するプロジェクトでは毎回Scalaでの開発をしつこく主張するでしょう。しかしながら、私の発言力が及ばない他のチーム、部署、他社、世間に関しては「Scalaは便利ですよ」とお勧めはするものの、それ以上の領域には絶対立ち入りません。だって、そんなのはそれぞれの組織が自力で考えることですし、私が頑張ってScalaを広めても私にメリットは無いですからね。Scalaプログラミングを教える講師とかという立場だったらまた別ですが。

ともかく、私の考えでは言語なんてどうでもいい。それでも私がScalaにこだわるのは長期的に見たら学習コストをペイできるほど仕事が楽になると思っているから、です。