From: "Mark Wilden said:
Hmmm. Is it that objects change their type, or is it that variables do?
I don't see variables in ruby as having any type at all. They merely
hold a reference to some object (any object.)
If you think about it, the class of an object
is _continually_ being interrogated at runtime, in order to dispatch a
given message to the right method.
Ruby is more dynamic than that.
i'm turning "fancy" into a widget!
=> "ordinary"
In my view, neither the variable 'x' nor 'y' changed in the
above example. The object referenced by 'y' definitely
changed. If an object's type is defined by what methods
it responds to, then the type of the object referenced by
'y' changed. But its class hierarchy did NOT change:
y.class => String
x.class => String
y.class.ancestors => [String, Enumerable, Comparable, Object, Kernel]
x.class.ancestors
=> [String, Enumerable, Comparable, Object, Kernel]
The only way to tell that the object referenced by 'y'
responded to :to_widget was to ask it. However, in ruby,
even asking doesn't always prove anything:
i'm turning "fancier" into a widget!
=> #<Widget:0x2c95b18>
The use of method_missing is a perfectly valid programming
approach in ruby, used often to forward method calls on to
some delegate, or also used to manufacture previously
nonexisting methods on-the-fly.
An example of the latter is the Og (Object Graph) ORM
library.[1] One can invoke methods on a class representing
a database table, without said methods previously existing:
class IPHost
property :ip, String, :unique => true
property :hostname, String
end
rec = IPHost.find_or_create_by_ip_and_hostname("1.2.3.4", "example.com")
Og is smart enough, using method_missing, to notice that
the method name begins with find_or_create_by_... and as
I recall it does a fairly simple split(/_and_/) on the
remainder of the method name to determine the column names
being referenced.
For optimization purposes, Og may also then define that
method dynamically, so that it will now exist to speed up
further invocations. (But, semantically, of course, there's
no need for the method to literally be defined, as it could
continue to handle it via method_missing.)
One further small point of interest. Notice that IPHost
doesn't inherit from anything. (Except Object, by default.)
When the Og library is initialized, it reflects through
ObjectSpace looking for classes which have used its
roperty
method to define database columns. And it includes an
appropriate module on such classes to imbue them with the
smarts they need to function.
All of the above being reasons why in Ruby, duck typing is
preferentially approached as "tell, don't ask."
There is no infallible way to ask objects whether they
respond to a particular method, so just Trust The Programmer
and call the method you expect to be there. In the more
rare cases (like the OP in this thread) where one finds a
need to ask, then ask the particular object if it responds
to the method in question. Because querying its class
inheritance hierarchy, as we have seen above, is about the
least reliable and most overly restrictive approach.
[1] Og:
http://oxywtf.de/tutorial/1.html
Regards,
Bill