静的型付け言語 crystal

41
静的型付け言語 Crystal Crystal The Programming Language with Static Typing Hirofumi Wakasugi (@5t111111)

Upload: 5t111111

Post on 21-Jan-2018

1.932 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: 静的型付け言語 Crystal

静的型付け言語 CrystalCrystal The Programming Language with Static Typing

Hirofumi Wakasugi (@5t111111)

Page 2: 静的型付け言語 Crystal

Crystalは静的型付けの プログラミング言語です。

Page 3: 静的型付け言語 Crystal

静的型付け• 変数などの型はコンパイル時に決定されている • 型チェックによって事前にバグを捕捉しやすい

• 変数などの型は実際の実行時の値になる • 柔軟で再利用性の高いプログラムを書きやすい

動的型付け

Page 4: 静的型付け言語 Crystal

動的型付けのRubyと 静的型付けのCrystal どっちが優れてるかとか そういう話はしません!

Page 5: 静的型付け言語 Crystal

Crystalが 静的型付け言語として どのように働くか 淡々と見ていきます。

Page 6: 静的型付け言語 Crystal

変数の定義

a = 3 b = "we are like crystal, we break easy" c = [1, 2, 3]

• 変数 a の型は Int32 • 変数 b の型は String • 変数 c の型は Array(Int32)

変数は初めて値が代入されたときに宣言される

Page 7: 静的型付け言語 Crystal

変数の定義

• 変数 a の型は Int32 • 変数 b の型は String • 変数 c の型は Array(Int32)

変数は初めて値が代入されたときに宣言される

a = 3 b = "we are like crystal, we break easy" c = [1, 2, 3] 型推論

Type Inference

Page 8: 静的型付け言語 Crystal

変数への再代入

これはどうなる? エラーになってしまうの?

すでに宣言されて型が決まっている変数に代入する

a = "we are like crystal, it is not easy" a = 100

Page 9: 静的型付け言語 Crystal

変数への再代入

別の型を変数に代入してもエラーにはならない 変数の型は代入される式 (値) によって型推論される

すでに宣言されて型が決まっている変数に代入する

a = "we are like crystal, it is not easy" # ここで変数 a は String a = 100 # ここで変数 a は Int32

Page 10: 静的型付け言語 Crystal

Arrayの型

これはどうなる? いけそうじゃない?

Int32のArrayにString型の要素を追加する

a = [1, 2, 3] a << "we are like crystal"

Page 11: 静的型付け言語 Crystal

Arrayの型Int32のArrayにString型の要素を追加する

a = [1, 2, 3] a << "we are like crystal"

no overload matches 'Array(Int32)#<<' with types String Overloads are: - Array(Int32)#<<(value : Int32)

a << "we are like crystal" ^~

これは コンパイルエラー

Error

Page 12: 静的型付け言語 Crystal

空のArray型を指定せずに空のArrayを宣言することはできない

a = [] # Syntax Error a = [] of Int32 # OK!

ということは、 異なる型の要素を含むArrayは 作れない?

Page 13: 静的型付け言語 Crystal

Union型

ArrayはGeneric型であり、(Union型を含む) 要素の型を指定できるHashなど、他のコンテナ (コレクション) 型も同様

型の組み合わせを表現するUnion型

a = [1, 2, 3, "we are like crystal"] #=> Array(String | Int32) a = [] of String | Int32 #=> Array(String | Int32)

Page 14: 静的型付け言語 Crystal

Generic型(後で説明しますしません)

Page 15: 静的型付け言語 Crystal

メソッド呼び出し

これはどうなる? エラーになってしまうの?

ある型 (クラス) に存在しないメソッドを呼び出した場合

a = 3 a.size

Page 16: 静的型付け言語 Crystal

メソッド呼び出しある型 (クラス) に存在しないメソッドを呼び出した場合

a = 3 a.size

undefined method 'size' for Int32

a.size ^~~~

これは コンパイルエラー

Error

Page 17: 静的型付け言語 Crystal

メソッド引数

def put_size(x) puts x.size end

put_size("crystal") put_size(5)

undefined method 'size' for Int32

puts x.size ^~~~

Error

引数で渡されたオブジェクトにメソッドがない

Page 18: 静的型付け言語 Crystal

型制約

def put_size(x : String) puts x.size end

put_size(5)

no overload matches 'put_size' with types Int32 Overloads are: - put_size(x : String)

put_size(5) ^~~~~~~~

Error

引数に型アノテーションを指定し型を制約する

Page 19: 静的型付け言語 Crystal

型制約があると安心だね!引数はどんどん型制約しよう!

Page 20: 静的型付け言語 Crystal

Re: メソッド引数

def put_size(x) puts x.size end

put_size("crystal") put_size([1, 2, 3])

引数で渡されたオブジェクトにメソッドがある

えっ?

Page 21: 静的型付け言語 Crystal

Re: メソッド引数

def put_size(x) puts x.size end

put_size("crystal") put_size([1, 2, 3])

引数で渡されたオブジェクトにメソッドがある

7 3

Result

エラーなく正常終了する

Page 22: 静的型付け言語 Crystal

Re:

def put_size(x) puts x.size end

put_size("crystal") put_size([1, 2, 3])

引数で渡されたオブジェクトにメソッドが

7 3

Result

エラーなく正常終了する

明確に型制約がされていなければ、ある型が呼び出されるメソッドに応答するとき、コンパイラの型チェックは通る。

Page 23: 静的型付け言語 Crystal

ダックタイピング的な型システム

型そのものやその継承関係に依存しない、 柔軟性を持った静的型付けになっている

シグネイチャが特に重要であるという点で、Structural Subtyping (構造的部分型付け) と言ってもよいかも

Page 24: 静的型付け言語 Crystal

Re: Re: メソッド引数

def put_size(x) puts x.size end

put_size("crystal") put_size(5)

undefined method 'size' for Int32

puts x.size ^~~~

Error

型制約をしなくてもコンパイル時にエラーが捕捉される

不必要な型制約は柔軟性を欠く

Page 25: 静的型付け言語 Crystal

インスタンス変数インスタンス変数も代入される値から型推論される

class Person getter name

def initialize(@name) end end

barney = Person.new "Barney" barney.name #=> "Barney" barney.name.size #=> 6

Page 26: 静的型付け言語 Crystal

barney = Person.new "Barney" barney.name.size one = Person.new 1

Re: インスタンス変数インスタンス変数に異なる型を与えて初期化

なんかおかしいとこある?

Page 27: 静的型付け言語 Crystal

barney = Person.new "Barney" barney.name.size one = Person.new 1

Re: インスタンス変数インスタンス変数に異なる型を与えて初期化

undefined method 'size' for Int32 (compile-time type is (String | Int32))

barney.name.size #=> 4 ^~~~

これは コンパイルエラー

Error

Page 28: 静的型付け言語 Crystal

if var.is_a?(…)is_a? で型をチェックし制限する

if a.is_a?(String) # ここでは a が # String で「ある」ことが保証される else # ここでは a が # String では「ない」ことが保証される end

コンパイル時リフレクションによる型の保証

Page 29: 静的型付け言語 Crystal

if var.responds_to?(…)responds_to? で応答をチェックし制限する

if a.responds_to?(:size) # ここでは a が # size に応答「する」ことが保証される else # ここでは a が # size に応答「しない」ことが保証される end

コンパイル時リフレクションによるメソッド応答の保証

Page 30: 静的型付け言語 Crystal

Re: Re: インスタンス変数is_a? や responds_to? で制限する

if (name = barney.name).is_a?(String) name.size #=> 4 end

if (name = barney.name).responds_to?(:size) name.size #=> 4 end

インスタンス変数の場合は、上記のように一度変数に代入する必要がある

Page 31: 静的型付け言語 Crystal

asas で型を制限することもできる

name = barney.name as String name.size #=> 4

• asは実行時にチェックを行う • 対象がStringでなかった場合には例外が発生 • asはキャストではない (別の型への変換はしない)

Page 32: 静的型付け言語 Crystal

nil-ableある型がNil型を持つ可能性

a = [] of String? a.class #=> Array(String?) a << "crystal" #=> ["crystal"] a << nil #=> ["crystal", nil]

• String?は型がNil型を持つことを意味する

• (String | Nil) というUnion型と同様

Page 33: 静的型付け言語 Crystal

nil-able インスタンス変数initializeで初期化されないインスタンス変数

class Person getter name property address

def initialize(@name) end end

barney = Person.new "Barney" barney.address = "Manchester" barney.address.size

Page 34: 静的型付け言語 Crystal

nil-able インスタンス変数initializeで初期化されないインスタンス変数

barney = Person.new "Barney" barney.address = "Manchester" barney.address.size

undefined method 'size' for Nil (compile-time type is String?)

barney.address.size ^~~~

Error

これは コンパイルエラー

initializeで初期化されないインスタンス変数はNil型を持つ

Page 35: 静的型付け言語 Crystal

Re: nil-able インスタンス変数インスタンス変数をinitializeの外側で初期化する

class Person getter name property address @address = "nowhere"

def initialize(@name) end end

barney = Person.new "Barney" barney.address = "Manchester" barney.address.size #=> 10

Page 36: 静的型付け言語 Crystal

インスタンス変数の型指定インスタンス変数を型アノテーションで指定する

class Person … @address :: String … end

• @addressにString以外の型を代入するとエラー

• 型のデフォルト値は存在しないので初期化は必要

Page 37: 静的型付け言語 Crystal

まとめ

• Crystal ≠ Ruby • 中でも静的型付けによる違いは非常に大きい

それでも、 We love Ruby's efficiency for writing code.

というのがCrystalの出発点の1つであるように、 Rubyの柔軟性や生産性、気持ちいい書き味を維持して 静的型付けにしようとする工夫が随所に見られる。

Page 38: 静的型付け言語 Crystal

話せなかった話題たち

• Generic型 (Generics) • 例外処理内での型推論の働き • クロージャ内での変数の型 • マクロにおける型情報へのアクセス • typeof、Object#tryなどのメソッド • etc. etc.

Page 39: 静的型付け言語 Crystal

http://ja.crystal-lang.org/docs/

今日話せなかった内容もドキュメントに記載があります

Page 40: 静的型付け言語 Crystal

ドキュメントをいつもup-to-dateにするために 翻訳を手伝ってくれる方を募集しています

GitHub https://github.com/crystal-jp/ja.crystal-lang.org

Gitter https://gitter.im/crystal-jp/ja.crystal-lang.org

もしくは @5t111111 まで直接お知らせください!

Slack http://crystal.pine.moe/

Page 41: 静的型付け言語 Crystal

本スライド中のサンプルコード およびその出力内容は すべて Crystal 0.9.0 で確認しています

ご静聴ありがとうございました。