新世代オブジェクト指向言語Scalaの魅力 · インプレス・ジャパン...
Transcript of 新世代オブジェクト指向言語Scalaの魅力 · インプレス・ジャパン...
0
新世代オブジェクト指向言語Scalaの魅力
2011/12/01 Scala コミュニティ 水島 宏太
1
※所属会社の業務とScalaに関係はありません
氏名:水島宏太
株式会社イーフロー所属の1エンジニア
Scala関連の記事・書籍執筆・勉強会発表等 余暇の時間で 刺激を求める技術者に捧げるScala講座(第6回・第17回担当、第23回・24回(執筆中))
日経BP ITProの連載コーナー
http://itpro.nikkeibp.co.jp/article/COLUMN/20080613/308019/
オライリージャパン 『プログラミングScala』 (レビュー)
秀和システム 『Scala実践プログラミング―オープンソース徹底活用』(共著)
インプレス・ジャパン 『Scalaスケーラブルプログラミング第2版』 Scala 2.9解説記事執筆
プログラミングの魔道書 vol.2. 『プログラミング言語Scalaの歴史とこれから 』 寄稿
Scala Days 2010(スイス), Scala Days 2011(アメリカ) 参加・発表
その他多数
プログラミング言語・構文解析好き 自作のプログラミング言語Onion等をgithubで公開
自己紹介
2
Java VM上で動作するプログラミング言語
Javaの資産はほぼ完全に利用可能
Glue Code不要
静的型を持ったオブジェクト指向言語
クラス、オブジェクトと言ったJavaの概念はそのまま利用可能
高速な処理系
「Javaらしい」コードはJavaとほぼ同じ速度
「Scalaらしい」コードも十分に高速
型推論による冗長な記述の排除
静的型による安全性はそのままに
不変オブジェクトを中心とした安全で強力なコレクションライブラリ
XMLリテラルの言語・標準ライブラリによるサポート
簡潔なXML処理
標準ライブラリでActorをサポート
明示的なロック不要の並行処理記述ライブラリ
標準ライブラリにパーザライブラリ同梱
カスタムDSLや設定ファイルのパーザを尐ない工数で書ける
Scalaの概要
3
2002: スイス連邦工科大学ローザンヌ校(EPFL)で開発開始
主要開発者:Martin Odersky
javac (Java 5以降)オリジナル開発者 && Java Generics提案者の一人
2003: 最初の公開版リリース
2005: ~Scala 1.X
2006: Scala 2.0リリース~Scala 2.5リリース
2007: Scala 2.6リリース
2008: Scala 2.7リリース
Java Genericsと互換に
2008: TwitterによるScalaの採用(バックエンド処理の置き換え)
2010: Scala 2.8リリース
2011: Scala 2.9リリース
2011: Typesafe社設立
CEO: Martin Odersky, CTO: Jonas Bonér(Scala製ミドルウェアAkkaの開発者)
Scalaの商用サポート、コンサルティング、IDEプラグイン開発等
"Typesafe Stack"の提供
2011: Typesafe社、Play 2.0 Frameworkの商用サポート発表
Scala年表
4
※ 公開されている事例のみ紹介 Twitter LinkedIn Foursquare Amazon.com VMWare Novell Xerox NASA Bank of America UBS Remember the Milk Siemens GridGain OPOWER The Guardian その他多数
Scala採用事例(海外)
5
※ 公開されている事例のみ紹介
株式会社パテントビューロ
Webサービス開発などの主力言語としてScalaを採用
知財判例データベース、astamuse(特許情報閲覧・検索サービス)等
有限会社ITプランニング
Scalaによるシステム構築事例
GMOメディア株式会社
リワード広告システム等
株式会社ドワンゴ
導入予定
参考: ドワンゴ社内 scala勉強会(ニコニコ生放送)
http://live.nicovideo.jp/watch/lv71111927
等
Scala採用事例(国内)
6
Scala勉強会 in 渋谷 (rpscala)
渋谷・秋葉原などで毎週勉強会を開催
Akasaka.scala
赤坂を中心に勉強会を開催
天領倉敷Scala
岡山付近のScalaコミュニティ
大阪Scala勉強会
Scala勉強会@東北
オンライン上の勉強会をほぼ毎週開催
東日本大震災の影響で休止中
名古屋Scala勉強会
名古屋を中心に活動
Scala@福岡
福岡を中心に活動
国内のScalaコミュニティ・勉強会
Hello, Scala
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, World!")
}
}
class Hello {
public static void main(String[] args){
System.out.println("Hello, World!")
}
}
Hello, Worldプログラム (Scala)
Hello, Worldプログラム (Java)
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, World!")
}
}
Hello, Worldプログラム (Scala)
さようなら, null. こんにちは, Option[T].
「null参照の概念は10億ドル単位の過ち 」 by アントニー・ホーア
Option型によって、「nullを取り得る型」を区別
// nullを取りうるか型から判別できない
String x = map.get("key");
// String y = x; // コンパイルできる
String y = x == null ? x : "default";
nullを使ったプログラム片 (Java)
// 「失敗する」可能性が型から判別できる
val x: Option[String] = map.get("key")
// val y: String = x // コンパイルエラー
val y: String = x.getOrElse("default")
Optionを使ったプログラム断片 (Scala)
お手軽型推論
自明な型をコンパイラが推論(型推論)
自明でない型(メソッドの引数等)は書く
// 自明な型でも書かなければいけない
Map<String, List<String>> map =
new HashMap<String, List<String>>();
Map型の変数宣言 (Java)
val map = new HashMap[String, List[String]]()
// 型を書いても良い
val map: Map[String, List[String]] = ...
Map型の変数宣言(Scala)
無名クラスのシンタックスシュガー
いわゆる「関数リテラル」と呼ばれているもの
実体は単なる無名クラスのシンタックスシュガー Java 8のラムダ式(予定)と異なり、変更可能な外部変数も参照可能
関数型プログラミングを知らなくても使える
val multiply = new Function2[Int, Int] {
def apply(x: Int, y: Int): Int = x * y
}
println(multiply.apply(5, 10))
val multiply = (x: Int, y: Int) => x * y
println(multiply(5, 10))
ケースクラス(case classes)
よくある「値オブジェクト」のクラス定義を簡潔に記述できる
case class Person(name: String, age: Int)
// ...
val person = Person("hoge", 18)
値オブジェクトのクラス定義と生成(Scala)
class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public String getAge() { return age; } } //... new Person("hoge", 18)
値オブジェクトのクラス定義と生成(Java)
Loanパターン (VS. Java 7 ARM(Automatic Resource Management)) (1)
Loanパターン: リソースの自動closeを「ライブラリとして」提供
Java 7 ARM: リソースの自動closeを「構文として」提供 dispose()等でリソース破棄するライブラリには使えない
// 一度「ライブラリとして」定義すれば def using[T <: Closeable](resource: T)(block: T => Unit): Unit = try { block(resource) } finally { resource.close() } // 組み込みの構文のように使える using(new FileInputStream("input.txt")){in => for(b <- Stream.continually(in.read()).takeWhile(_ != -1)) Console.out.write(b ^ 0xFF) }
Loanパターン(Scala)
try ( FileInputStream in = new FileInputStream("input.txt"); ) { int b; for (int b; (b = in.read()) != -1 ) { System.out.write(b ^ 0xFF); } }
ARM(Java 7)
Loanパターン (VS. Java 7 ARM(Automatic Resource Management)) (2)
SWTでの比較: dispose()でリソースを解放
case class Wrapper[T <: { def dispose() }](core: T) extends Closeable{ def close() : Unit = core.dispose() } def wrap[T](core: T): Wrapper[T] = Wrapper(core) val display = new Display() using(wrap(new Shell(display))){ case Wrapper(shell) => /* ... */ shell.open() while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep() }
SWT + Loanパターン(Scala)
Display display = new Display(); Shell shell = new Shell(display); /* ... */ try { shell.open(); while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep(); } finally { shell.dispose(); // dispose()なので、ARM構文が使えない }
SWT (Java 7)
強力なコレクションライブラリ (1) 簡潔な記述
より重要なロジックに集中できる
List<Person> persons = new ArrayList<Person>();
/* ... */
List<String> namesAged18 = new ArrayList<String>();
for (Person p: persons) {
if (p.getAge() >= 18) namesAged18.add(p.getName());
}
if (namesAged18.size() > 0) {
System.out.print(namesAged18.get(0));
namesAged18 = namesAged18.subList(1, namesAged18.size());
}
for(String name: namesAged18) System.out.print(", " + name);
フィルタリング処理 (Java)
val persons = List[Person](...)
// 年齢が18歳以上の人の名前のリストを抽出
val namesAged18 = persons.collect{ case p
if p.age >= 18 => p.name }
//カンマで区切って出力
print(namesAged18.mkString(", "))
フィルタリング処理(Scala)
強力なコレクションライブラリ (2) 不変と可変
「不変」コレクションと「可変」コレクションを別の型として管理 可読性の向上 + コレクションの取り扱いミスを防御
「型はドキュメント」の思想をJavaより進めている
// Listは可変
// (a) 防御的なコピー
// (b) Collections.unmodifiableList()
// 引数にそのまま渡すのは危険
String concatWithLn1 (List<String> namesIn) { ... }
// 「そのまま」渡す必要がある
String concatWithLn2 (List<String> names) { ... }
リストの文字列を連結するメソッドのシグニチャ(Java)
// Listは不変なので安全に引数として渡せる
def concatWithLn1(names: List[String]): String = ...
// ArrayBufferは可変なので、中で変更され得る事がわかる
def concatWithLn2(names: ArrayBuffer[String]): String = ...
リストの文字列を連結するメソッドのシグニチャ(Scala)
サンプルプログラム:XML処理
Twitterのpublicタイムラインのユーザから スクリーン名
フォロワー数
を取得して、フォロワー数(降順)でソートして表示
val timeline = XML.load( new URL("http://api.twitter.com/1/statuses/public_timeline.xml") ) val info = for(user <- timeline ¥¥ "user"; name <- user ¥¥ "screen_name"; follower <- user ¥¥ "followers_count" ) yield (name.text, follower.text) val sorted = info.sortBy{ case (name, followers) => - followers.toInt } for ((name, count) <- sorted) { printf("Name: %s%n", name) printf("Followers: %s%n", count) }
Twitterのpublicタイムライン取得プログラム
サンプルプログラム:XML処理(実行結果)
$ "scala Timeline.scala" で実行可能 コンパイルと実行が同時に行われる
Name: PreferKobayashi Followers: 1953 Name: PapaDock_TFF Followers: 1380 Name: dida34 Followers: 1359 Name: DeLaAsia Followers: 699 Name: olivacarden Followers: 444 Name: ReflectSound Followers: 171 Name: _KEYBUMMIE Followers: 167 Name: ElPadrino_2595 Followers: 145 Name: bubych Followers: 144 Name: ranrats Followers: 140 Name: MaryKateMolina Followers: 138 Name: jpii777 Followers: 96 Name: dee_jo_freshh Followers: 94 Name: nova_luna Followers: 87 Name: dedLavanza Followers: 75 Name: RichieMinaj88 Followers: 27 Name: hazelsnutz Followers: 25 Name: cogancool Followers: 7 Name: bellgos6 Followers: 3 Name: telurodebiz Followers: 0
18
scalacコマンド
javacに相当(クラスファイルへのコンパイラ)
オプションもjavacと類似した部分が多い(-classpath等)
fscコマンド
scalaコンパイラをサーバとして常駐させて、コンパイルを高速化するコマンド
それ以外はscalacと同じ
scalaコマンド
1.scalacで生成されたクラスファイルを簡単に実行
2.scalaスクリプト(テキスト)をそのままコンパイル・実行
3.対話環境(REPL)
Scala/Java APIの動作を調べたい時に便利
scaladocコマンド
javadocコマンド相当
sbazコマンド
scalaアプリケーション/ライブラリ用のパッケージマネージャ
基本ツール(標準添付)
19
sbt Scalaのデファクトスタンダードなビルドツール
ビルド設定ファイルをScala DSLとして記述
Apache Ivyベース
Mavenリポジトリをそのまま利用できる
Mavenと同じディレクトリ構成を採用
簡単な記述で、Scalaの各種ライブラリに対する依存関係を記述可能
ScalaTest/Specs Scalaにおける2大ユニットテスティングライブラリ
ScalaTestの方が保守的、Specsは新機能を積極的に取り込む傾向
ScalaCheck (半)自動テスティングライブラリ
テスト対象の型からテストケースを自動生成
ScalaTest/Specsを補完
準標準ライブラリ/フレームワーク
sbtのビルド設定ファイル例
単純なプロジェクトなら、これだけでOK
No more XML hell
必要であれば、Scalaのプログラムを設定ファイルに書ける
// プロジェクト名 name := "Simple Project" // バージョン version := "1.0" // 組織 organization := "hoge" // ビルドに使うScalaのバージョン scalaVersion := "2.9.1" // ライブラリの依存性記述 libraryDependencies ++= Seq( "org.specs2" %% "specs2" % "1.6.1", "org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test" )
Build.sbt
21
Lift Scala用Webアプリケーションフレームワーク XMLリテラルなどScalaの機能を活用 企業における採用実績一定以上あり (Foursquareなど) Ajax/Cometアプリケーション開発のための便利なAPI
Play! Java/Scala用Webアプリケーションフレームワーク Ruby on Rails(RoR)ライクな開発サイクル 2.0からコードベースをScalaに移行(Java用 APIは引き続き提供)
Scalatra RubyのSinatraフレームワークに影響を受けたフレームワーク 小規模Webアプリケーションの開発に適している フレームワークの仕組みを理解するのが簡単
Unfiltered httpサービスを提供するためのライブラリ/ツールキット(≠Webアプリケーションフレームワーク) no view 簡潔な記述で、URLに対応するサービスをつなげられる Remember the Milk等で採用
Finagle Twitter製 Scala用RPCライブラリ JBoss Nettyベース
Casbah MongoDBのScala用API MongoDB開発元の10gen謹製
その他多数
主要Webアプリケーションフレームワーク/ツールキット
22
IntelliJ IDEA Scalaプラグイン IDE開発が公式に提供しているプラグイン 最も高機能・安定性が高い Java -> Scala変換のような、マイグレーションのための機能 自動リファクタリング
Java/Scala混在プロジェクトもうまく扱える
コード補完
Scala IDE for Eclipse Typesafe社に管理が移行 急速に品質が改善 自動リファクタリング(名前変更・メソッド抽出など、現時点では限定的) コード補完
NetBeans Scalaプラグイン 個人での開発 コード補完など、基本機能は揃っている インストールするのがやや面倒
主要IDEプラグイン
23
簡潔なコード 実用的にはJavaの1/3~1/4程度のコード量 冗長なJavaコードを「書く」のはIDEがサポート 冗長なJavaコードを「読む」のは労力が必要
より安全なコード 不変オブジェクトを作りやすい言語設計
Javaでライブラリ化(できない/現実的でない)部分をライブラリ化可能 Don't Repeat Yourself(DRY)原則 リソースの自動クローズ(Loanパターン)
Java 7では「言語仕様の拡張」が必要だった Scalaでは、単なるライブラリとして提供できる 一般化: 前処理 -> 本処理 -> 必ず実行される後処理 をライブラリ化可能
ロック不要の並行処理記述ライブラリ(Actor) マルチスレッドプログラムのバグ削減に有効
コレクションライブラリ Java:
標準では「可変」コレクションのみ提供(「読み込み専用」に変換するメソッドはある) 型から「可変」、「読み込み専用」、「不変」のどれを意図しているかがわからない
Scala: 標準で、不変コレクション/可変コレクションの両方を提供 型から「可変」、「読み込み専用」、「不変」コレクションのどれかが判別できる 不変コレクションは安全に複数スレッド間で共有可能
領域特化言語(DSL)を簡単に作成できる Actor、パーザライブラリなど
Scalaの採用メリット
24
学習のための良いドキュメント(日本語)不足
「読んですぐScalaを使える」 ドキュメント(チートシート)があまり無い
所謂「コップ本」は速習には向いていない
国内におけるScala開発者の尐なさ
新しい言語には付き物の問題
誮がコードをメンテナンスする?
商用サポート
Typesafe社による公式商用サポートは英語前提
日本語の商用サポートは未定
Scalaライブラリにバグがあった場合どうするか
Scalaの採用リスク
25
言語仕様はJavaよりも複雑
「言語の全てを把握していないと使えない」なら学習コストは高い
言語仕様の複雑さ≠言語の学習コスト(難しさ)
Perl, Ruby, PHP等の言語も言語仕様から言えば複雑
全てを最初から覚える必要は無い
「Better Java」から始める
構文を除いて、Javaとの高い互換性を持っている
「JavaプログラムのようなScalaプログラム」はすぐ作れる
要: Java構文 -> Scala構文 のチートシート
Java -> Scala自動変換器(IntelliJ IDEA Scalaプラグイン)が存在
型推論・ライブラリの恩恵はすぐに受けられる
「Scalaらしいプログラム」への緩やかな移行が可能
リスク回避策(1): Better Javaから始める
26
JavaソースとScalaソースが混在したプロジェクトをビルド可能
尐しずつScalaを導入できる
ユニットテスト用DSL(領域特化言語)としてScalaを導入
ScalaTest/Specs
カスタムDSL実装用言語としてScalaを導入
パーザライブラリ等
scalaコマンド(対話環境)の活用
Java APIの挙動をすぐに確かめるのに便利
Scalaの習得のためにも使える
実行結果がすぐ返ってくる
リスク回避策(2): 部分的に使い始める
27
Scalaは関数型プログラミングを覚えないと使えない? NO
関数型プログラミングを知っていた方が「より良い」
知らなくても、「新しい静的型付けオブジェクト指向言語」として使える case classによる簡潔なValue Objectの定義
無名クラスのシンタックスシュガー
ジェネリックス
強力なコレクションライブラリ
型推論
Option型
オブジェクト指向と関数型のハイブリッド?
アカデミックで難しそう
実用的ではない
色々な機能をごちゃまぜ?
学習コストが高い
IDEサポートが貧弱?
IDEが無いとちょっと…
Scalaに関するFAQ(1) – 関数型プログラミング
28
Scalaは複雑なので、習得が難しい? NO
言語仕様の複雑さ ≠ 習得難易度 いわゆるLL(Perl, Ruby, PHP)も言語仕様は「複雑」
言語仕様の全てを知らなくてもプログラムは書ける
ただし 汎用Scalaライブラリを開発するなら、ある程度の仕様理解は必要
「汎用ライブラリ設計者」にとっては習得が難しい かもしれない
「ライブラリユーザ」にとっては習得はそれほど難しくない
いかにして両者を切り分けるかが誯題
Scalaに関するFAQ(2) – 複雑さと学習曲線
29
Scalaはオブジェクト指向と関数型のハイブリッド? No
Javaの仕様をリファクタリングして、型推論やDSL、関数型プログラミングサポート等を統合した静的型付けオブジェクト指向言語
(Java – staticメンバ – プリミティブ型 - …) + 型システムの拡張 + 型安全なコレクションライブラリ + ... = Scala
追加した部分だけではなく、削った部分がある
Scalaはごった煮言語? No, but ...
Scalaの設計哲学は「統合」
比較的尐ない概念でより様々な事を表現できるように進化
1つの概念で様々な面を表現可能
概念の数が多いと誤解しがち
Scalaは「実用」言語
コミュニティの成長によって、「統合」哲学にそぐわない機能の要望も
結果として、ad hocに見える仕様が追加/維持される事がある
Scalaに関するFAQ(3) – 設計思想
30
IDEサポートが貧弱で使い物にならない? No, but ...
主要IDEに関しては「使える」レベルに達している Eclipse Scalaプラグイン
IntelliJ IDEA Scalaプラグイン
NetBeans Scalaプラグイン
IntelliJ IDEA + Scalaプラグインが最も高機能・安定性が高い
しかし 各種IDEのJavaサポートの完成度にはまだ及ばない
自動リファクタリング、補完、コード生成などの面
IDEのサポートをどこまで期待するか
Scalaに関するFAQ – IDEサポート
31
Eclipse + Scala IDE for Eclipse
NetBeans + Scalaプラグイン
IntelliJ IDEA + Scalaプラグイン
デモ