注意 ここにある内容はpony2.x時代にドキュメントに書かれていた物なので、もう古い可能性が高いです。最新の情報は公式ドキュメントを参照してください。
はろぽにー₍₍ (ง´・_・`)ว ⁾⁾
前回でCapabilitesでましたけど、じゃあコンパイルが通ると何が保証されているのかはぼんやりしたままでした。
ということで今回はそのへんをやります。 本家だとこの辺です。→ http://tutorial.ponylang.org/capabilities/guarantees/
Guarantees
reference-capabilities
の意味は前回だいたい紹介しましたが、他のアクターに渡せるとか何がmutableで何がimmutableなのかを把握しておくことは安全な並行処理プログラミングを行うために非常に重要です。
Mutable reference capabilities
mutableなreference capabilitiesはiso
, trn
, ref
の三つです。
それぞれについて何が保証されるか見ていきます。
reference capability | その変数自身 | 自アクター の他の変数 | 他アクターの変数 |
---|---|---|---|
iso | read/write ○ | read/write × | read/write × |
trn | read/write ○ | read ○ / write × | read/write × |
ref | read/write ○ | read ○ / write ○ | read/write × |
以上の表のようにmutableなreference capabilities
では他アクターからその変数の値を読み取ることさえ出来ません。
自アクターが変数を書き換えてしまうのでそりゃそうですよね。
一方で自アクター内では微妙に違いがあります。それぞれの特長は以下のようになっています。
iso
は、 read/writeユニーク です。その変数をread/writeすることができる唯一の変数です。trn
は、 writeユニーク です。その変数にwriteすることができる唯一の変数です。readは自アクターなら誰でもできます。ref
は、 特にユニークではありません。その変数を書き換える他の変数がいるかもしれませんし、他の変数から値を読み取ることが出来ます。
他アクター内ではreadできないからデータ競合が起きないのは分かるけど、なんで自アクター内でもreadやwriteを制限するのか?という疑問については他アクターへ参照を渡すときを考えると分かりやすいです。例えばiso
であれば、今持っている他アクターへiso
な変数の参照を渡すと同時に自アクターで持っていた参照を無効にすれば、そのデータへのread/writeユニーク性は保たれます。一方でref
だと一つのref
を向こうにしても他に参照がいるかもしれませんから、ちょっと向こうにしたところで結局、他のアクターへ安全に渡すことが出来ません。このように自アクター内でも制限を設けることでアクター同士のデータのやりとりの際にどういうデータなら渡しても安全か、を規定することができます。(詳しくは今後の章で解説され(ると思い)ます。)
Immutable reference capabilities
immutableなreference capabilitiesはval
, box
, の二つです。
それぞれについて何が保証されるか見ていきます。
reference capability | その変数自身 | 自アクター の他の変数 | 他アクターの変数 |
---|---|---|---|
val | read ○ / write × | read ○ / write × | read ○ / write × |
box | read ○/write × | read ○ / write ○(注1) | read ○(注1) / write × |
注1: 排他になる。(どちらか一方が○だったら、もう一方は×になる)
それぞれの特長は以下のようになっています。
val
は、globally immutableです。誰も値を変更することが出来ないため、様々なアクターから安全にreadが可能です。box
は、locally immutable です。box
な参照を通しては値を変更することはできません。しかし、他の自アクター内の変数が値を変更するかもしれません。また、box
な参照を持つデータがval
な場合は他のアクターから値をreadすることができます。
box
がなんだか複雑ですが、以下の状況を思い浮かべると分かりやすいと思います。
actor Main new create(env: Env) => var trn_s: String trn = recover String().append("test") end var box_s1: String box = trn_s var val_s: String val = "test" var box_s2: String box = val_s
trn_s
はtrn
なので自アクター内ではwriteが可能です。一方で他のアクターからtrn_s
やbox_s1
が参照しているデータをreadすることはできません。
val_s
はval
なので自アクター内でのwriteは出来ません。一方で他のアクターからval_s
やbox_s2
が参照しているデータをreadすることができます。
Opaque reference capabilities
最後の一種類はtag
です。tag
な参照はreadもwriteも出来ません。オブジェクトの同一性の判定には使うことが出来ます。
Aliasing
エイリアシングっていうと大したことは無いと思うかもしれませんが、Ponyのaliasingはちょっと考える必要があります。
aliasing and deny gurantees
ここでいうaliasingは例えば
fun test(a: Wombat iso) => var b: Wombat iso = a // Not allowed!
のようなことを指しています。参照に別名がついているのでaliasingです。コードのコメントにも書いてありますが、単純に同じ型とreference capabilitiesを持つa,bに対して b = a
を行うことができません。a, bともにiso
な参照なのでaliasingするとread/writeユニークな保障が崩れてしまうからです。
bがtag
なら以下のように代入を行うことが出来ます。
fun test(a: Wombat iso) => var b: Wombat tag = a // Allowed!
tag
はreadもwriteも出来ないので、iso
をaliasingしてもread/writeユニークが保たれるからです。
aがtrn
の場合、bがbox
である必要があります。
fun test(a: Wombat trn) => var b: Wombat box = a // Allowed!
bがiso
だとaが参照を持っているのでダメです。bがval
だとaが変更できてしまうのでダメです。bがref
だとtrn
のwriteユニークが満たされなくなるのでダメです。bがtag
の場合はOKです。
変換を表にまとめると以下のようになります。
from | to |
---|---|
iso | tag |
trn | box, tag |
ref | ref, box, tag |
val | val, box, tag |
box | box, tag |
tag | tag |
iso
とtrn
が自分自身に変換できないので、うっとなりますがそれ以外は大丈夫なのでなんとかなりそうです。
read/writeユニークなiso
のaliasingは厳しい。writeユニークなtrn
はbox
を通せば見れる。と頭に入れておきましょう。
aliasingはいつ行われるか?
aliasingは代入したとき、引数として渡した時に発生します。
ephemeral types
isoな値は代入することができないので、val a: Foo iso = Foo.createIso()
のようなことをすることができません。
それは困るのでephemeral type
という型を用意します。ここでFoo.createIso()
がiso
ではなくiso^
を返すようにすると、
受け取ってくれたら、自分はすぐに参照を破棄するよ〜といった意味になります。
返り値の型がiso^な関数は以下のように作ることが出来ます。
fun test(a: Wombat iso): Wombat iso^ => consume a
consumeについては後ほど解説されますので、今は ^
がついてたらiso
で受け取っていいんだなと思っておきましょう。
trn
に関してもtrn^
で同じことが出来ます。
alias types
ephemeral typeと同じような理由でalias typeという概念があります。
fun test(a: A) => var b: A! = a
のようにするとA!
は「何でもいいからAから安全にaliasできる型」という意味になります。
終わり
Ponyでは同じ型(というかreference capabilities)同士で代入することすらできないことが判明しました。 これでは色々不便というか実用できるのか!という気分になりますが、次回に出てくるconsumeを学べば色々便利になるのでこうご期待です₍₍ (ง´・_・`)ว ⁾⁾