"Paul Brannan" <pbrannan / atdesk.com> schrieb im Newsbeitrag news:20040615171413.GY2788 / atdesk.com... > On Tue, Jun 15, 2004 at 12:08:37AM +0900, Robert Klemme wrote: > > You need to return 'copy' here. > > Good catch, thanks. > > > > 3. Should dup be implemented in terms of clone or should clone be > > > implented in terms of dup (or should they both be implemented > > > independently or in terms of another function)? > > > > IMHO neither since #dup and #clone do have different semantics with > > respect to freeze. Well, you could do something like this: > > > > class Foo > > attr_accessor :foo, :bar > > > > def dup; do_copy( super, :dup ); end > > def clone; do_copy( super, :clone ); end > > > > protected > > def do_copy(copy, sym) > > copy.instance_eval do > > @foo = @foo.send sym > > @bar = @bar.send sym > > end > > > > copy > > end > > end > > I like this, since it works on both 1.6 and 1.8. > > > but this does not work for #clone if the instance is frozen. > > Right, because the copy has already been frozen when we start to modify > it. I wonder if there's a good way around that (without using > initialize_copy, since that doesn't work on 1.6). Maybe I should > re-implement clone/dup in ruby (as you've done below) for Object so that > it has the same behavior as 1.8. Well, you could reimplement #clone in terms of #dup and apply all changes (freeze and taint) aftewards. You'll be quite likely to end up with a similar scheme to #initialize_copy, so the question is whether it's worthwile. > > This might be better: > > > > It's much better, though it seems a bit heavyweight. > > > class Foo > > attr_accessor :foo, :bar > > > > def clone; copy :clone; end > > def dup; copy :dup; end > > > > protected > > def copy(sym) > > c = self.class.new > > > > copy_init c > > > > c.freeze? if frozen > > c.taint if tainted? > > I think this should read: > > if sym == :clone then > c.freeze if frozen? > c.taint if tainted? > end Yes, of course! Thank you! > > c > > end > > > > def copy_init(c) > > c.instance_eval do > > @foo = @foo.sent sym > > @bar = @bar.sent sym > > end > > end > > end > > > > class Bar < Foo > > attr_accessor :name > > > > protected > > def copy_init(c) > > super > > c.instance_eval do > > @name = @name.send sym > > end > > end > > end > > > > > > > 4. When making the copy, is super the right way to make the copy, or > > > should allocate be used? (allocate doesn't work on 1.6.x, which I > > > still use heavily, though if it's the right solution, then it's the > > > right solution). > > > > I'm inclined to follow the Java clone() pattern and use super. Of course > > you can also just do self.class.new. > > The problem with self.class.new is that the initialize method may have > some semantics that are undesirable when copying. Exactly. > > > 5. Certain types cannot be dup'd (e.g. NilClass in all versions of Ruby > > > or Fixnum in 1.8 and later), so the above code will break if I write: > > > > > > Foo.new(10, 42).dup > > > > > > Is it possible (or is it even wise) to write a dup or clone function > > > that works with both value types and container types? > > > > It depends on whether you expect these types as members and what you want > > to be done with them. It's difficult to anwer this generally, that's why > > the automatic methods just do a shallow copy. > > > > Generally speaking IMHO NilClass#dup should return self, same for Fixnums > > and others. But OTOH I can see why Matz did it this way: so you get to > > know that some instance is not cloneable. > > That's exactly what I was thinking, though I was hoping for a better > answer. :-) Maybe Matz has some other reason. Kind regards robert