Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

RubyKaigi2014 速報(4) - KeyNote: Coming soon... (Matz)

Ruby 3.0について

  • 10年位の期間がかかるかもしれないが、考えてみよう
  • ひとつはConcurrency、ひとつはJIT (LLVM?)、そしてStatic Typing

Static typing

  • 20世紀に生まれた言語の多くは、変数に型が無い

    • 最近の言語: Scara, TypeScript, Dart, Goはスクリプト言語っぽい使われ方をされるものでも、静的な方を持っている
  • 悔しいのでRubyでも静的型を考えたい

    • Ruby Issue #9999: Type Annotations
    • Python PEP:3107 に近い考え方
      • Pythonは型チェックしない。ドキュメント。型チェックするかどうかは処理系に任せる
      • pypy という処理系ではチェックする
    • また、Dartは型チェックしないモードもある
  • 何をモチベーションにして static typing したいのか?

    1. パフォーマンス
    2. コンパイル時のチェック
    3. ドキュメンテーション

パフォーマンス

  • 速いことは良い。速すぎる!という人はいないが、遅すぎる!という人はいる
    • パフォーマンスのために静的な型が必要なのか?というと、そうでもない
      • JSのV8、LuaJITはパフォーマンスが良い
      • パフォーマンスは実装している人の労力によってきまる: JIT, Specialization
      • 動的な型でパフォーマンスを向上することも出来る

CompileTimeCheck

  • 多くのプログラムは型の矛盾を含むので、それをチェックすることでバグを見つけることが出来る
  • 例えば、リファクタリングの時に引数の型や数でチェックできる
  • 一気に纏めてフィルタリング出来るのは嬉しい

  • ただし、型を導入すると柔軟性が落ちる

    • DuckTypingは静的型付けと相性が悪い

Documentation

  • Rubyでは、どのようなデータを渡せばよいかというのは、コメントや変数名で推測している
  • 型情報があると、安心してデータを渡せる。つまり、信頼性の高い優れたドキュメントになる
  • 処理内容を見て推測しなくても良くなる

今までなぜ型がなかったのか?

  • 最大の理由は、無くても動いたから
    • DuckTyping: もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである
    • Rubyは文字列の様に振る舞うものであれば、ちゃんと渡せる
      • "文字列"を渡します、と定義すると、文字列しか渡せない
    • 静的な型を導入すると、これまでのRubyが積み上げてきたDuckTypingの美しい世界が破壊される。これは嬉しくない

Rubyへの導入を考える

  • 元々型がないので、Optionalなものにならざるを得ない

    • 型のない世界から型のある世界にいくと、型情報が落ちてしまう
    • Optionalなものにしてしまうのと、ほんの一部しか型チェックが出来ない
    • TypeScriptは決定的に型をつけている。既存のJSライブラリには外から型情報を与えられるので、99%型が存在する。そういう世界では型情報が嬉しい
  • Rubyの世界に型情報を入れると、それはRubyと言っていいのか?

    • やはり違う言語になる

    どこかのPで始まる言語のように、V5とV6で全く違う、ということにしたくない

  • DRY( Don't Repeat Yourself )

    • 同じことを2回書くのは嫌。Static Type を書けと言われると、抵抗がある
    • プログラムの本質はコンピュータにどんな仕事をさせたいか伝えること
    • 型はこのようなことをしますという情報。それは本来処理をみれば意図がある。 それで、型を書きたくないと思ってしまう

Soft-Typing という考え方

  • 宣言なしで、コードからこういう処理はこういう型を持っていると推測する
  • 一種の型推論: ベストエフォートな型チェックをする
  • 例えば、どんなメソッドが呼ばれているか、どんなメソッドの引数にしているか
    • a=1 # type of a integer
    • def foo(a); print a.to_int; end
      • foo(1) # OK: 1 has to_int
      • foo("a") # NG: "a" does not have to_int
  • それを広い範囲で行うと、プログラム全体の静的なチェックをある程度行うことが出来る

型はメソッドの集合で定義される

  • メソッドが型を定義可能
  • それはどんなメソッドの引数になるか
  • どんな値を戻すか
  • 場合によっては Class で判断できる

お行儀の良いプログラムをすると多分できるが、Rubyはお行儀の悪いプログラムもかける言語

  • 言語自信のサブセットを対象にすることになるであろう
  • 対象となる範囲のクラスが狭い。機能的な制限ではない
  • requireを制限する、define_method, method_missiong はtype check できない

Subset

  • 静的な型チェックの範囲を制限すると、型を書かなくてもコンパイルのときにチェックできる

    • ただし、Documentationとしての働きは出来ない
    • しかし、人間が宣言しなくても、プログラムが意図を汲み取って推測することが出来る
    • compilerに型を教えるのではなく、compilerが確認を取ってくれる
      • 例えば、compileの方の推測によってエディタが補完することが出来る
      • また、compile time のエラーによって提案することが出来る
  • Ruby3.0で入ると約束は出来ないが、記事を書いたので見て欲しい

    • 日経Linux 2014年9月号/10月号? 9/11月号?
  • Subsetの考え方はその他に応用できるとも考えている

    • スタンスは、Subsetの範囲内でプログラミングするといいことが有ります、外れると恩恵は受けられないけど、今まで通り書けます
    • これで Compativility を維持できる
  • 未来のRubyは、Soft-TypeとDynamic-Typeの2つを持つ

    • 今まで通りのRuby
    • ボーナスがある方向に誘導していけば、サブセットがある方向に変えていける

さいごに

  • 現時点ではCrazyなアイデアに過ぎないが、そろそろ新しいことを始めようではないか、と思っている

Ruby3.0の道の扉を開いた。新しいことを始めよう。死なないように未来を妄想しよう

質問

  • Q: Subsetの考え方は、パフォーマンスが悪い書き方を警告する、という風に使える?

    • A: 出来ると思う。良い書き方をすれば速くなる。サブセットという考え方は他の色々なものに応用が出来ると考えている
  • Q: 今までRubyに静的な型を導入しようという研究があったが、流行らなかったのはどう考えている?

    • A: ひとつは、RubyのFull set に型推論だけで型を付けるのは不可能。どういう制限を付けるか?ということが重要で、サブセットがそのよい解決法と考えている。そもそも型を書くのは難しい。型一致ではなくてコード一致というのを後から導入するのは難しい。
  • Q: サブセットが小さすぎると困る。ifが問題になると思う。ANDにすると両方の型を持つ変数にしなければいけない

    • A: ifはORになるのではないかと思っている。つまり、どちらの型でも良い
    • 提案: define methodはプログラムの開始時に動いて、メタプログラミングしないというがよくあるケースなので、ひと通り初期処理が終わったと(判断するのは難しいが)利用者側で定義フェーズを指定できれば良い