[#45318] Windows コマンドプロンプトで UTF-8を出力するには — Yuumi Yoshida <yuumi3@...>

おつかれさまです、 Yuumi3です。

11 messages 2008/08/08

[ruby-list:45436] Re: cloneの挙動について

From: Akira Hayakawa <ruby@...>
Date: 2008-08-30 02:16:05 UTC
List: ruby-list #45436
西塔さん、たけさん、ありがとうございました。
解決しました。

つまり、
=によるコピーされた変数に対する単純代入だったら、守られるけど、
replaceのようなオブジェクトに影響する更新メソッドの場合は、シャローコピーだと、
属性は共有しているという点で、オリジナルまで響いてしまうという事ですね。
つまり、私のプログラムではシャローコピーとディープコピーの違いを検証する事が不可能だったと。

動的言語は、振る舞いから型が決まるので、もしかしたらルートにあるObject型のcloneを使えば、
どのノードにあるクラスもディープコピーされてしまう神(なのかどうかは知りませんが、不変オブジェクトを返すという意味では)仕様なのかと思いましたが、
やっぱりObject分のメモリはディープコピーで、その他はオーバーライドしない限りはシャローコピーという仕様なんですね。

ちなみに不変オブジェクトを返すという点において、
http://c2.com/ppr/wiki/JavaIdioms/ImmutableInterface.html
このような方法をとる人もいて、それは私もなのですが、Rubyでは他の方法を考えなければいけませんね。
でも、ダックタイピングがあれば、ラッパーだろうがなんだろうが、中間に挟む為に書き換える場所がめちゃくちゃ少なくて済む事に気づきました。
こういうのは型から振る舞いを決めるより振る舞いから型を決めた方がずっと柔軟になりますね。

素晴らしいです。
ドキュメントについても、結局、動的言語と静的言語の差が、型が書いてあるかどうかなので、
型についてだけ書いておいて、それで分からないなら静的で書こうが結局意味不明なコードという事になるので、さほど心配する必要がない事が分かりました。

On Sat, 30 Aug 2008 10:53:49 +0900
take_tk <ggb03124@nifty.com> wrote:

> たけ(tk)です。
> 
> [ruby-list:45431] cloneの挙動について にて 
> Akira Hayakawa <ruby@i-mail.jp> さん 曰く:
> 
> > .cloneをしないと、私が"Brad Pitt"になってしまって、べ、べつに嬉しくなんかないんだからねっ!
> 
> ブラッドピットに変身できますけど・・。
> 
> a = Man.new(Name.new("Akira"))
> p a.get_name
> #p a.get_name.name = "Brad Pitt"
> p a.get_name.name.replace "Brad Pitt"
> p a.get_name    #=> #<Name:0x13220fc @name="Brad Pitt">
> 
> −−−−
> 
> どういう結果を望んでいるのかよくわからないので、一般論として述べておきま
> す。
> 
> 一言で言えば、あるオブジェクト(a)でcloneすると、レシーバのオブジェクト(a)
> 自体は別のオブジェクトに複製されて別のオブジェクトになる(b)が、その属性
> (name_obj)は複製されない。元のオブジェクト(a)と新しいオブジェクト(b)とは
> 属性(name_obj)を共有する状態になる。
> 
> その場合でも、一方のオブジェクト(b)の属性代入(name_obj=)で属性のオブジェ
> クトを入れ換えれば、共有状態が解消されるので問題を生じない。
> 
> しかし、属性の内部状態を(属性のオブジェクトの同一性を保ったままで)変更
> すると、他の共有者の状態に影響する。
> 
> * 他の共有者(b)の属性(name_obj)の属性(name_str)に代入すれと、属性
> (name_obj)の内部状態が変る。しかし属性(name_obj)のオブジェクトの同一性は
> 保たれるので、共有者(a、b)による属性(name_obj)の共有状態は解消されない。
> よって、他の共有者(a)に影響することになる。
> 
> −−−−
> 
> class NameObj
>   attr_accessor :name_str
> 
>   def initialize(name_str)
>     @name_str = name_str
>   end
> end
> 
> class Man
>   attr_accessor :name_obj
> 
>   def initialize(name_obj)
>     @name_obj = name_obj
>   end
> end
> 
> # cloneしても属性のオブジェクト(name_obj)は共有している。
> # 他の共有者(b)で属性のオブジェクト(b.name_obj)の内部状態を変更すれば、共有者(a)の状態も変る。
> 
> a = Man.new(NameObj.new("Akira"))
> b = a.clone
> b.name_obj.name_str = "Brad Pitt"
> p a    #=> #<Man:0x1320e28 @name_obj=#<NameObj:0x1320e3c @name_str="Brad Pitt">>
> p b    #=> #<Man:0x1320e14 @name_obj=#<NameObj:0x1320e3c @name_str="Brad Pitt">>
>   #       ↑               ↑
>   # Manのオブジェクトは異なるが、NameObjのオブジェクトは同じ。もちろんname_strのオブジェクトも同じ。
> p a.name_obj.name_str.object_id  #=> 10028800
> p b.name_obj.name_str.object_id  #=> 10028800
> 
> # 共有者(b)の属性代入(name_obj=)であれば、属性のオブジェクトが入れ代わるので、
> # 他の共有者(a)の状態には影響が無い。
> 
> a = Man.new(NameObj.new("Akira"))
> b = a.clone
> b.name_obj = NameObj.new("Brad Pitt")
> p a    #=> #<Man:0x13207ac @name_obj=#<NameObj:0x13207c0 @name_str="Akira">>
> p b    #=> #<Man:0x1320798 @name_obj=#<NameObj:0x1320770 @name_str="Brad Pitt">>
>   #       ↑               ↑
>   # Manのオブジェクトは異なる(clone)、NameObjのオブジェクトも異なる(属性代入)。
> 
> −−−−
> 
> class NameObj
>   attr_accessor :name_str
> 
>   def initialize(name_str)
>     @name_str = name_str
>   end
> ##    # NameObj#clone で name_str のクローンを作る
> ##  def clone
> ##    new_obj = super
> ##    new_obj.name_str = @name_str.clone
> ##    new_obj
> ##  end
> end
> 
> class Man
> ##  attr_writer :name_obj
>   attr_accessor :name_obj
> 
>   def initialize(name_obj)
>     @name_obj = name_obj
>   end
>   
>     # Man#clone で name_obj のクローンを作る
>   def clone
>     new_obj = super
>     new_obj.name_obj = @name_obj.clone
>     new_obj
>   end
> end
> 
> # Man#clone で name_obj のクローンを作れば
> # name_obj のオブジェクトも変る。
> 
> a = Man.new(NameObj.new("Akira"))
> b = a.clone
> b.name_obj.name_str = "Brad Pitt"
> p a    #=> #<Man:0x1320950 @name_obj=#<NameObj:0x1320964 @name_str="Akira">>
> p b    #=> #<Man:0x1320928 @name_obj=#<NameObj:0x1320914 @name_str="Brad Pitt">>
>   #       ↑               ↑
>   # Manのオブジェクトは異なる、NameObjのオブジェクトも異なる。name_strのオブジェクトは??
>   
> # これ(↑)で、うまくいくようにみえるのだが・・・
> # 実は、二つの NameObj(a.name_obj と b.name_obj)とは属性(name_str)のオ
> ブジェクトを共有している。ので、
> # name_str を破壊的に変更すると・・
> 
> a = Man.new(NameObj.new("Akira"))
> b = a.clone
> b.name_obj.name_str.replace "Brad Pitt"
> p a    #=> #<Man:0x1320824 @name_obj=#<NameObj:0x1320838 @name_str="Brad Pitt">>
> p b    #=> #<Man:0x13207fc @name_obj=#<NameObj:0x13207e8 @name_str="Brad Pitt">>
>   #       ↑               ↑
>   # Manのオブジェクトは異なり、NameObjのオブジェクトも異なるが。name_strのオブジェクトは同じ。
> p a.name_obj.name_str.object_id  #=> 10028070
> p b.name_obj.name_str.object_id  #=> 10028070
> 
> take_tk = kumagai hidetake
> 
> 


-- 
Akira Hayakawa <ruby@i-mail.jp>

In This Thread

Prev Next