Hatena::ブログ(Diary)

Oh, you `re no (fun _ → more) このページをアンテナに追加 RSSフィード

Ah well, a dromedary has one hump and a caml has reference cells, buffers, and a garbage collector.

2014-06-11

大事なことは全部MLが教えてくれた 〜 Apple の Swift の mutability 周りの件を理解する

開発者アカウントに金が出せない貧乏人の方々が、次の Apple の Swift のコードの挙動がわからない、というので盛り上がっております:

let a = [1,2]          // a = [1,2]
var b = a;             // b = [1,2]
b[1] = 3;              // a = [1,3]  b = [1,3]
b.append(5);           // a = [1,3]  b = [1,3,5]
b[1] = 4;              // a = [1,3]  b = [1,4,5]

だいたい

  • b[1] = 3 とやると a[1] も変化する、これがわからないという人
  • b[1] = 4 とやると a[1] が変化しない、これがわからないという人

二種類いるようです。私はまず、 b[1] に代入できることがわかりませんでしたのでそれ以前の人間です。

こういうとき、このコードが何をやっているかを理解するには同じ挙動をする ML のコードを書くとわかりやすいです。なぜ ML かというと、もちろんみんなの好きな関数型言語であって、かつ代入などの副作用を持っていて、でも基本は不変データなので可変データの部分はちゃんと明示してやらなきゃいけない言語なので、こういう副作用でわけわからんコードを読み解くには明示する分都合がよろしいからです。もちろんみんなが好きな関数型言語というのはここではとくに意味がありません。Haskell は本題に行く前に Haskell は純粋で純粋なのに副作用があったりなかったりうだうだモナドがああだこうだで圏論があしたどしたでドヤってめんどくさ過ぎるのでこういうのには向きません。

で、書くとこんなんになります。 http://try.ocamlpro.com/ で一行づつ入れながら、途中で a;; とか b;; して変化を見ながら試してみるといいよ:

let a = [| 1; 2 |];;
let b = ref a;;
!b.(1) <- 3;;
b := Array.append !b [|5|];;
!b.(1) <- 4;;
  • b[1] = 3 とやると a[1] が変化するのがわからない人は、 var b = a がコピーは行わないってことをわからない人です
  • b[1] = 4 とやると a[1] が変化しないのがわからない人は、b.append(5) が b 自体を変えてしまうことがわからない人です、ってかこれ普通わかんないでしょ

でもこれ両方とも ML で書いたコードではハッキリわかりますよね。少なくともこの例を見る限りは、

  • var b = e は e の値への参照を作るだけでコピーはしない
  • b.append(5) は参照する値に 5 をくっつける。配列だから結果はコピーになる。 b はそこに参照先を変える

という意味だとわかる。(Array.append はコピーするんですよ。というか配列の後ろに何かつけてもコピーじゃないってそんなすごい配列があったらそれは配列じゃない) copy-on-write とかカッコイイ機能を入れようとしたけどバグっているんだ!とかそういうオシャレ事案ではない。

クソですね。

オブジェクトメソッド呼び出しのような外見なんだけど、呼ばれた後、オブジェクト自身は他のに摩り替わっている。高度なナリスマシ事案だ。

せっかくだから Apple の Swift の人の立場になって考えましょう。これはどう直せばいいですかね。

  • var b = e は e の値のコピーを作ってそれを参照することにする

これはパフォーマンス落ちる…のなら、気休めに copy-on-write 導入しますか。 b[1] = 3 とやっても a[1] が変わらない… まあよく判んない人相手にはこの挙動が一番いいのかもしれませんね。

  • 配列を頭よくして b.append(5) とやっても b の中身は成りすましにならず、ちゃんと b[1] = 4 の後 a[1] = 4 になる。

これは配列はもはや配列ではなくて何か別の rope みたいなものになります。うーんそれは配列ではない。

  • b.append(5) などというクソいメソッドはやめて b = b ++ [5] みたいにする。

これならコピーしていることがわかる?かな?いやー無理でしょうねぇ。

この中でどれが一番いいか…やはり ML を使うことだと思いますね。おわり。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/camlspotter/20140611/1402457362
おとなり日記
  • 2014-06-11 Cli@ 3/58 5%