Scalaと向き合い続けてゆく - Re.Ra.Ku アドベントカレンダー day 20

Re.Ra.Ku アドベントカレンダー 20日目です。

こんにちは。近藤です。

今日も今日とてScalaのお話です。しかしコードはほとんど出て来ません。

さて、この記事をご覧の方々はScalaに対してどんなイメージを抱いているでしょうか?Scalaにまったく触れたことがない方、Scalaを少しだけ触ったことがある方、Scalaを普段からお使いの方、もちろんそれ以外にも触れたことのあるレベルに違いはあるでしょう。そして抱くイメージにも違いがあるかと思います。

そして私は一貫して「難しい、そして楽しい」というイメージを抱いています。

たしかにScalaに触れ始めたころは難しいところもありました。でもそれを使いこなしているときの楽しさも並ではありません。

私がScalaに触れ始めたのは4年ほど前だった気がしますが、そのときは趣味程度で触れていただけで、実務として触れているのはここ1年だけです。そんな中どう向き合ってきたかを振り返ってみます。

いきなり難しいことをしない

Scalaを使い始めるのはとても簡単です。JREやScalaをインストールすればいつでも始められます。

それでもいざ書こうとすると、やれ関数型だとか、やれ型だとか、そういう囁きがまとわりつくものです。ていうかまあ実際そうです。

ただそうだからといって、最初からそれを望むことはないと思います。関数型に無理にこだわらなくても書けます。型は制約ですので、それを定義する側は知らなくてはいけないことが多いですが、使う側にとっては型に縛られているからこその安心感があります。

それらを享受しつつ、ベターJava程度のものとして使っていく方が導入としては気楽かと思われます。

文法は多岐に渡っているように見えるだけ

新しいプログラミング言語に触れれば、当然新しい文法を知らなければなりません。とは言え、文法上は他のプログラミング言語と類似していることも少なくないため、受け入れやすいことも多々あります。

ただ個人的な感想で言うと、Scalaの文法は比較的複雑だと思います。というか、ひとつのことに対する書き方が多いです。

しかし書き方が多いだけで、噛み砕いてしまえばなんてことが無かったりします。私の感じたことで言うと、関数の呼び出しでしょうか。例えばこんな関数があります。

def execIf(condition: => Boolean)(exec: => Unit): Unit =
  if (condition) {
    exec
  }

名前渡し(Call-by-name)を使っていたりはしますが、引数リスト (condition: => Boolean)(exec: => Unit) の2つを取る関数です。呼び出し方は以下の通りです。

execIf(age >= 20)(println("age is over 20"))

そして以下のようにも呼べます。

execIf(age >= 20) { println("age is over 20") }

{} を使っていますね。Scalaの {} は式の集合で、その集合の最後の式の結果が {} 自体の結果となります。つまり:

execIf(age >= 20)({ println("age is over 20") })

と自由に {} で囲ってもなんら問題はありません。そしてこの場合関数呼び出しのための () を省いても構いません。よって:

execIf(age >= 20) { println("age is over 20") }

と書けるわけです。これであたかもifのように見える構文となります。そして名前渡しを利用することによって関数側で参照されるまで評価されないように出来ます。さらに {} は式の集合なので、複数の行を書いても構いません。

とまあこんな風に関数呼び出しひとつ取ってもいろいろな書き方があります。コードを読むときや、「こう書きたいんだけど……」というときにどう定義すれば良いか分からなかったりします。ただとあるルールといくつかの手法の組み合わせなことが多いです。

これはひとつひとつ学んで飲み下していく他ありません。私のおすすめはScalaスケーラブルプログラミング、いわゆるコップ本です。頭から順に読めばほとんどの疑問は解決するかと思います。覚えるということに近道もなければ魔法もないと思うので、Scalaに興味があるのであれば是非とも。

コンパイラは魔法ではない

Scalaを使う側は気楽だと言いましたが、ずっと使う側でいるなんてことはないと思います。例えフレームワークやライブラリを書かないとしても、プログラミングは抽象化の連続であり、いつかどこかで抽象化しなくてはいけないときが来ると思います。

そしてScalaにおける抽象化は、型との闘いです。型パラメータ、型クラス、上限境界/下限境界、変位指定などなど。この辺りを駆使すると、使う側にとって嬉しいものが出来上がります。それとコードでの表現力がグッと高まります。

この辺りも小さく始めていけば良いとは思いますが、いずれは遭遇するもの。このとき大切なのがコンパイラの気持ちになって考えるというものです。……自分で言っておいて何ですが、胡散臭いですね。

ただまあ言えることとして、コンパイラも魔法ではありません。とあるルールに沿っているわけです。そのルールが複雑でないとは言い切れませんが、複雑怪奇というほどではなく、人間が追うことは十分可能だと思います。

さきほど挙げた型にまつわる概念ですが、これらは型推論があるからこそ実用的なものであると考えています。関数(メソッド)を呼ぶときに型を指定することってあまりないと思いますが、これはどこかに型の情報があって型推論が働くからです。どうやって働いているかですが、ちゃんと自分の頭で考えてあげると十分辿れます。何度も言いますが魔法じゃありません。

とは言いつつ、implicit conversionのように「え、そんなところまで頑張っちゃうの!?」的なやつもあるにはあります(感じ方には個人差があります)。

まあ結局は「Scalaスケーラブルプログラミングを読もう!」となってくるのですが、この辺りは読んだだけでは掴み切れないものかもしれません。しかしやっていくうちに案外染み付いてきます。やっていきましょう。雑でマッチョな考えですが、そういうものだと思います。

私感

今まで述べたものはあくまで個人の感想です。私がここ1年で感じたことばかりです。

「うっわ意味分からん……」というのは何度も感じました。コンパイラと4時間格闘した末に妥協のコードを書いたことなんてザラです。しかし向き合うことで「分かった!!!」と大声上げたくなることもありました。

Scalaは難しいと思います。少なくとも私の頭でいきなり理解に及ぶことはありません。「これ考えた人は天才だな……。それを私が理解できるのか……」という卑屈なことは何度も思いました。いや、本当にライブラリなどを書けるようになるのか心配でしたからね!?それでも少しずつやっていったらなんとか出来ていったわけです。

Scalaに詰められたおもしろい考え方、それを理解して次第に書けるようになってゆく喜び、その上で現実の問題にぶち当たっていく。そのあたりに私は楽しいと感じるみたいです。

最後に

何をおもしろいと捉えるかは人それぞれですが、知ることが好きな人であればScalaのそれは非常におもしろいと思います。興味のある方は是非ともご自身の手で触れてみてほしいです。

それとですね、私が言っていますし、Re.Ra.Kuで使われているプログラミング言語とその選択理由でも触れられていますが、リラクではサーバサイドにScalaを採用しています。「もっと詳しい話聞かせて」だとか、「遊びに行ってみたいな〜」という方は是非お声掛けください。私宛には@takkkunにリプライいただければOKです。

そんなこんなでScalaの楽しさを分かり合える方が増えればと密かに思っております。それでは。