はじめに
初めまして。2011年度入社のつちはしと申します。
アメーバのゲーム部門でエンジニアをしています。
今回はエンジニアブログを書く機会を頂きましたので、大好きな Scala について書かせていただきました。
「たのしさ」というとらえどころのない話しゆえ、すこしゆるーくなっておりますが、ご了承くださいませ。
というわけで、よく「Ruby は使っていて楽しいお 気持ちいいお」と聞くけど、
Scala も楽しいし気持ちいいんだよー!
とゆうのを伝えたいです。。 伝わるといいです。。
(この記事は私が Scala の楽しいと感じる部分に的を絞って書いています。
Scala には楽しくない部分もいろいろありますが、それに関してはここでは触れません。
Scala たんは俺の嫁)
さくっと書いてためしてみることが出来るの
本題に入る前に。。Ruby には irb という、その場でプログラムを書いてすぐに試せるツールがありますが、 Scala にも似たようなものがあるんです。
Scala REPL といいます
Scala が入っている環境なら、コマンドラインから
$ scala
と入力すれば起動しますお。早速何か入力して、エンター押してみましょう~
println("hello world.")
mac で brew だったら
brew install scala
で Scala が入るので、ここから一緒に試してみましょうお
なにが楽しいのかな
というわけで、本題です~Scala は何が楽しいのかな?
うーん、うーん、と考えてみました
きっと楽しさは人それぞれなので、私の主観をたくさん含みつつ、以下の5つに絞ってみました
- マスコットがかわいい
- やりたいことが素直に書ける
- 言語仕様にわくわくできる
- 言語を拡張できる
- すてきな環境
いろいろありそうですが、私はこの5つかなーと
順番に見ていきますお~
■「マスコットがかわいい」
画像のライセンスが不明なので、リンクを。。http://subtech.g.hatena.ne.jp/secondlife/20090701/1246418689
あらかわいい
真夜中3時に障害対応していたって、この子の可愛さでがんばれますね(*ノ∀ノ)
■「やりたいことが素直に書ける」
プログラミングは本来楽しいものだと思うのです
けど、書きたいものと実際に書くものの間に乖離があるほど、楽しくなくなっていくと思うのですお
やりたいことをやろうとしたら、ちょっと邪魔が入った。みたいな感じでしょうか
考えるままに書けると、とても気持ちがいいものですよね
- 今までの考え方がそのまま使えること
- それがよりシンプルに実現できること
この2つかなぁと思うのです
Scala はこれらを満たしていると思うんです~
例を見ていきますね
コレクション操作の考え方
たとえば Ruby のコレクション操作はとても気持ちいいですそれは、 Ruby のコレクション操作の考え方に慣れ親しんでいるからで、
それがそのまま Scala でも使えたら、気持ちいいと思うんです
Scala でのコレクション操作は、こんな感じです
List(1, 2, 3).map(i => i * 2).foreach(i => println(i))
> 2
> 4
> 6
(*´Д`) あら気持ちいい・・
Scala の場合、もうちょっと自明のものを削ることも出来ますお
List(1, 2, 3).map(_ * 2).foreach(println)
文字列操作の考え方
Ruby は文字列操作も気持ちよくできます
Scala も気持ちがいいんですお
"hello_scala_world".split("_").map(s => s.capitalize).mkString("")> HelloScalaWorld
(*´Д`)
値としての関数という考え方
(ここは関数型言語の考え方を知っている人じゃないと、少し難しいかもしれません。関数型言語の考え方も Scala ではそのまま使える例として載せています。)
関数型言語では関数を値として扱うことができます
上のコレクション操作でも、関数を値として関数に渡していました
Scala の場合はこんなかんじですお~
// func という関数を受け取り呼び出す関数 def callCallback(func: String => Any) = { func("callback!!") } // print するだけの関数 def callback(s: String) = println(s) // callCallback に callback を引数として渡す callCallback(callback)> callback!!
代数的データ型とパターンマッチという考え方
(ここは関数型言語の考え方を知っている人じゃないと、少し難しいかもしれません。関数型言語の考え方も Scala ではそのまま使える例として載せています。)
関数型言語では代数的データ型というものを使うらしいですお
Wikipedia の例を Scala で書くと、こんな感じになりますお
sealed trait Node final case class Leaf(l: Int) extends Node final case class Branch(a: Node, b: Node) extends Node def depth(tree: Node): Int = tree match { case Leaf(_) => 1 case Branch(a, b) => 1 + depth(a).max(depth(b)) } val tree = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4))) depth(tree)> 3
(´;ω;`) うーん、オブジェクト指向に慣れ親しんだ身としてはわかりやすいですが、 Haskell と比べると冗長で見劣りしてしまう。。
こういうのをみると、 Scala はオブジェクト指向言語に関数型の考え方を取り入れたものなんだなぁ。。
という気がしてきます。 あくまでオブジェクト指向が主で、関数型の考え方でも組めますよ。というスタンスを感じます
余談ですが、この書き方は Visitor パターンの代わりとしても使えますね
よりシンプルな DTO
Java で DTO を作るとき、 getter や setter を定義した100行くらいのコードを書くことがよくありますScala はこれをより容易にしてくれます
case class User( name: String, age: Int)
こう書くことで getter, setter, コンストラクタ, clone みたいなもの等が定義されます~
Lombok みたいですね
モナ・・・
あいつはボクには難しすぎるお。。。■ 「言語仕様にわくわくできる」
次に、「言語仕様にわくわくできる」と楽しいなーと私は感じます言葉足らずでごめんなさいなのですが、
私は、統一感があって、しっくりくると「すごいなー たのしいなー」
と感じるのだと思います
幾つか例をみていきます~
データの生成の一般化
多くの言語では配列や連想配列等、組み込みのデータ構造が特別扱いされていたりします新しいデータ構造を作った場合、組み込みのデータ構造とは別の書き方をしないといけなかったりもします
Scala ではデータの作り方が統一されています。
val list = List(1, 2, 3) val array = Array(1, 2, 3) val map = Map( "モナド" -> "わかんない", )
自分でデータ構造を作るときも、同じように作ることができるので、
統一感があるなーとかんじますお
null の扱いの一般化
NULL に初めてであったのは C/C++ 言語でしたあの時から、私の悩みの種は尽きません
null ってなに? 0 なの? ポインタなの? なんなの!? またぬるぽ起きたし!
考えてみると、この定義は謎です。
val foo: Foo = nullFoo 型の foo に null が代入できるのであれば、 null の型は Foo 型のサブタイプでなければなりません。
じゃあ、 null の型はなあに?
Scala はこの点、少しだけ頑張っています
null の型は Null であり、 Null はあらゆる参照型のサブタイプと定義されています
Null は親クラスのメソッドをオーバーライドしており、
実行するとほとんどのメソッドが NullPointerException を投げるようになっています
null.toString> java.lang.NullPointerException
「すべてはオブジェクトである」という考えを頑張って実現しようとしている努力が可愛い Scala たん。。(*´Д`)ハァハァ
■「言語を拡張できる」
それと「言語を拡張できる」ことこれがとてもたのしいです!
- プロジェクト固有の構文を定義できたり
- 組み込み型にプロジェクト固有の処理を追加できたり
気軽に DSL みたいなものが作れそうですねー!
(やり過ぎるとマサカリが飛んでくるのできおつけるのお。。)
演算子の定義
Scala の演算子は、実際はメソッド呼び出しです例えばこんなのがあったとすると。。
1 + 2これはこんなメソッド呼び出しと同じです
1.+(2)
つまり、演算子を自分で作ることができます
case class Vector2(x: Double, y: Double) { def +(v: Vector2) = Vector2(this.x + v.x, this.y + v.y) } Vector2(1, 2) + Vector2(3, 4)> Vector2(4.0,6.0)
制御構造の定義
Ruby で見かける 3.times do xxx endこういうのを自分で作ることができます。
例えば、例外を無視する構文
import scala.util.control.NonFatal def ignoreException(f: => Any) { try { f } catch { case NonFatal(e) => } } ignoreException { println("hi!") throw new Exception }> hi!
標準ライブラリに面白い例がいろいろ入っているので、みてみるとたのしいですおー!
- Actor
- Try
組み込みクラスにメソッドを追加
Java 以外の様々な言語で、組み込みクラスやライブラリのクラスにメソッドを追加することができますScala の場合はこんな感じですお
implicit class MyString(val s: String) extends AnyVal { def hello = s"Hello! $s こんにちは!" } "よっしー".hello> Hello! よっしー こんにちは!
Java の String には、似た方法で Scala 独自の便利なメソッドがたくさん追加されていますお
for 式
Scala の for 式はとてもとてもおもしろいのです!Ruby 等と同様、 for 式はシンタックスシュガーで、
対象のインスタンスの map, flatMap, filter, foreach 等のメソッド呼び出しに置換されます~
つまり、 for の実際の意味はこれらのメソッドによって定義できるということ!
そして、 Scala の for はループのためだけのシンタックスシュガーではなく、さらに広い利用範囲をもっているのです。
これを使ったライブラリはこんなものがあります。
- Future と Promise
非同期処理の連鎖を for 式でシンプルに記述できます
マクロ
これを使用すると、コンパイル時にプログラムを生成することができますScala のプログラムをパースした結果をプログラムで処理し、新しいプログラムを作ることができます
マジック!
これを使ったライブラリにはこんなものがあります
- SLICK の direct embedding
Scala のプログラムから SQL を生成できます
- ScalaLogging
ログを出さない時はログ生成コードを一切実行しないようにできる、ログライブラリです
すてきな環境
最後に、言語のたのしさは環境によるところも大きいですすてきな Vim 拡張があったりすると、テンション上がりますよねー!
Scala の場合は IntelliJ IDEA に Scala プラグインを入れて準備は完了!
(Eclipse や Vim もあるけど、 私は IDEA が好き!)
考えるままにキーを叩くと、それを正確な補完でサポートしてくれる IDE がとてもいいやつにおもえます。
ライブラリの海に潜っていこう
困ったときは IDE で「定義に飛んで」みましょう!Scala の標準ライブラリだって、誰かの作ったライブラリだって、すぐにソースとドキュメントが読めますお。
(Scala に限らないけど) 使っているライブラリのソースをシームレスに参照できる環境ってすてきです~
最後に
長々と書いてきましたが、 Scala の楽しさがすこしでも伝わったら嬉しいです(*´∀`)
ぜひ一度 Scala を触ってみて、それがきっかけで、日本に、社内に Scala 好きな人が増えると嬉しいです~
(言語の選定をできる立場の方は、まずは自分で触ってみて欲しいのです。 Scala は Java の資産も使えますよ~)
ありがとうございました!