Hi -- On Sun, 18 Feb 2007, Greg Hurrell wrote: > I personally would like to see immutable objects like Nil and Fixnum > return self if sent a dup message. > > The problem with the currently model is that it makes it difficult for > the programmer to make a distinction between "by copy" ("by value") > and "by reference". The most obvious example to look at is instance > variables. > > There are some cases where you want your instance variables to be set > "by reference"; that is, where you are interested in a particular, > specific object and want to keep track of it, including changes in its > value, over time. Most often the kind of object you want to pass in by > reference is a high-level object that encapsulates some kind of > complex state and behaviour. > > There are also cases where you want your instance variables to be set > "by copy"; that is, where you are not concerned about the identity of > an object and only care about the value of the object at the time you > assign it to a variable. Most commonly the kinds of objects you'll > want to pass by copy are simple, primitive objects, usually numbers, > strings and values like nil. > > The trouble is not that Ruby passes everything "by reference" by > default, but that Ruby makes it hard for you to pass "by copy" ("by > value") when you want to. Imagine an instance variable for which > you've defined an accessor using "attr_accessor". By default this will > pass "by reference". > > If you want to pass "by copy" you have to manually write an accessor. > But if you write your accessor like this: > > def my_var=(value) > @my_var = value.dup > end > > You'll get exceptions whenever you pass nil (a very common case, I > would imagine). Change it to this: > > def my_var=(value) > @my_var = (value.respond_to? :dup ? value.dup : value) > end > > This works for nil, but it's not as readable because of the extra > punctuation. Try passing in a Fixnum though; you'll get an exception > because Fixnum claims to respond to "dup" but complains when you > actually send the message (pretty surprising). So you have to do this: > > def my_var=(value) > @my_var = value.dup rescue value > end > > To me this seems like an awful lot of work every time you want an > instance variable to be "by copy" ("by value") instead of "by > reference". Yes, you'll might have problems here if you pass in a > singleton-but-mutable object, but I assume that if you know enough > about what you're doing to specifically want things to be passed in > "by copy" ("by value") then you also know exactly what will happen > when try passing in a singleton-but-mutable object. > > As a programmer coming from Objective-C one of the current behaviour > was one the most annoying things about Ruby. Now I just write my > accessors using "rescue" whenever I want "by copy" behaviour. I > probably wouldn't have had to adopt this habit if classes like Nil and > Fixnum just returned self in response to the "dup" message. This is > the orthodox behaviour in Objective-C; in fact, even singleton-but- > mutable classes normally just return self if sent the "copy" message. > > An even more elegant solution, however, would be to extend > "attr_accessor" and friends to allow the programmer to specify if > attributes should be set "by copy" or "by reference". This is exactly > what the new Obejctive-C 2.0 provides. In those cases where you want > to override the default behaviour you would do a > "attr_accessor_bycopy :my_var" and Ruby would do the right thing. Of > course, there is nothing stopping me from writing my very own > "attr_accessor_bycopy" method, but it would be nice if it were a > feature of Ruby itself. One problem with this is that dup oeprations don't fall precisely along the lines of a by value/by reference/by copy categorization. If you do this: a = "hi" b = a.dup you're assigning to b a reference to a dup of a. If you do this: b = a you're assigning a reference (the one in a) by value to b. This stuff won't necessarily transliterate well from another language. I'd rather just keep what's happening on the surface: if you want a dup of an object, then call dup on it (with error handling if necessary). I think that's better than add a new layer of terminology to Ruby method names. (I'm also not sold on the idea of a method called "dup" harboring the possibility of silently returning something that isn't a dup, as discussed earlier in the thread.) Maybe we'll go down the road of flags some day: attr_reader(:dup => true) or something.... David -- Q. What is THE Ruby book for Rails developers? A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf) Q. Where can I get Ruby/Rails on-site training, consulting, coaching? A. Ruby Power and Light, LLC (http://www.rubypal.com)