Hi David,

dblack / wobblini.net wrote:
> I think I'm not understanding what you mean by the context of an
> object.  Your example involves two different objects (I assume), so
> I'm not clear on which object's context/type you're referring to.  Or
> do you mean the context in which a given method name appears?

"Context" here is the knowledge that certain methods are not only 
defined, but that they have certain semantics -- i.e. Can#open and 
Connection#open have the same name, but they do different things. If an 
object were both a can and a connection (but not necessarily instances 
of Can or Connection), it could define #to_can and #to_conn methods. 
Then any method requiring a can could call #to_can on the argument, and 
expect the #open method on the object returned to behave as expected. 
#to_can could of course return a Can instance, but I just don't see the 
reason why that should be the only option; that would mean that all cans 
must inherit from Can, which in this case of course is reasonable, but 
it isn't always. If we require that the object be of a certain class, we 
make inheritance about type, and not just behavior. That's why I think 
we should (where it's not absolutely necessary) disregard the class of 
the return value of the #to_* methods, and instead just expect it to 
behave properly.


>>  str = "foo"
>>  str.object_id         #=> 23456248224800
>>  str.to_str.object_id  #=> 23456248224800
> Well, at least it's not behaving differently :-)

Okay, bad example :P


> What I mean is: there's already a convention of using to_* for these
> class-specific conversion methods, so if you want to create a system
> of true type (as opposed to class) conversions, to_* might be a
> misleading name.
> 
> In other words, I'm not suggesting that how the core to_* methods work
> should be a model for how everything should work, but only that
> anything that doesn't work the way they work maybe shouldn't be called
> to_*.

You do have a very good point there -- the #to_* methods have been used 
in a rather non-quacky way. Perhaps #as_*?


Basically, I think of objects as pieces of information. This information 
can have several different representations, but the type should always 
be about the information, not the representation.

   class DollarAmount
     def initialize(amount)
       @amount = amount.to_f
     end
     def to_str
       "$#{@amount}"
     end
     def to_f
       @amount
     end
   end

Here the information is both the amount of dough, *and* the fact that 
it's in dollars, and not yen. There a two other representations of the 
instances of the class, a string and a float -- these representations 
contain less information than the original object would, but they can be 
manipulated in ways a DollarAmount can't, unless you define lots and 
lots of methods yourself.

The reason I think we should use the #to_* methods on received arguments 
(I'm not sure whether or not you agree that it's a good idea) is that I 
believe it to be the responsibility of a method to decide which 
representation of an argument it wants. One method may convert the 
DollarAmount to euro, so it needs the numeric representation -- but it 
should be smart enough to be able to receive a DollarAmount instance, 
and get the relevant representation itself.

   def dollar_to_euro(dollars)
     dollars.to_f * D2E
   end

The reason I think we should disregard the class of the objects returned 
by #to_* is that it decreases the flexibility of Ruby -- sometimes you 
want to create a completely different implementation of a "type", like, 
say, a hash, but with the exact same interface. An OrderedHash, perhaps. 
Should the author then be forced to have his class inherit from Hash, 
when really the implementation is completely different? #to_hash should 
return a hash, but must it be a Hash?


Daniel