最強に凶悪な #become:

Journal InTime で shugo さんが呈しておられる「いやな予感」 にもちょっとだけからめて、#become: のはなし。


#become: というのは、レシーバと引数(パラメータ)のポインタを交換してしまうメソッドです。曲がり角でぶつかると、僕と君が入れ替わるってあれですね(どれだ?(^_^;))。

| stringA stringB stringC |

stringA := 'string a'.
stringB := 'string b'.
stringC := stringB.

stringB become: stringA.

^ {stringA. stringB. stringC}   " => #('string b' 'string a' 'string a') "


Ruby にも、これとちょっとだけ似た挙動を示す String#replace というのがあります。でも、文字通り置き換えのみで、交換はされません。

strA = 'string a'
strB = 'string b'
strC = strB

strB.replace(strA)

p [strA, strB, strC]   #=> ['string a', 'string a', 'string a']


あと #become: は、a String 以外のオブジェクト同士も交換できます。

| fractionA fractionB fractionC |

fractionA := (1/2).
fractionB := (2/3).
fractionC := fractionB.

fractionB become: fractionA.

^ {fractionA. fractionB. fractionC}   " => #((2/3) (1/2) (1/2)) "


#become: の凶悪さはこれにとどまらず、クラスの違うオブジェクトだって平気で交換してしまいます。

| string fractionA fractionB |

string := 'string'.
fractionA := (1/2).
fractionB := fractionA.

fractionA become: string.

^ {string. fractionA. fractionB}   " => #((1/2) 'string' 'string') "


こわいですねぇ…。おそろしいですねぇ…。ただ、3 become: 4 はできないので少しだけ安心してください。w

3 become: 4   " => Error: can't become SmallIntegers "