Quoting flgr@ccan.de, on Tue, Mar 15, 2005 at 10:59:08PM +0900:
ES wrote:
>Possibly a bit too clever. While I like the reversal of roles in this
>fashion to facilitate the current implementation, I'm somewhat leery
>of the concept.
>
>First of all, an *single* explicit method is used, not the representative
>API of the class; for example in this instance, anything that defines
>#to_s
>could be considered to be valid input; sometimes more matching methods
>might be required. It is considerably harder to construct the idiom this
>way, so I can see the need for this compromise.
I'm not sure I get you there -- if anything that implemented .to_s would
be considered a String "5" == 5 would be true as well...
Just things implementing #to_str are considered a string.
>Secondly, the naming is confusing. #to_str? str is not a class and a very
>similar name #to_s does something different. A better choice would use the
>entire class name (lowercase would be fine) and clearly indicate that
>it's
>not necessarily being made into another class but used as an instance of
>the other class; hence SomeClass#as_string or something similar like my
>favourite SomeClass#quack_like_a_string.
I also think that :as_string would be clearer, but I'm not sure if
having to learn this is worth the hassle of breaking compatibility and
perhaps causing more confusion than good.
#to_str doesn't mean that something is a String. It means its a
"str"ing. String (built-in) and Pathname, Exception, and any other class
#to_str "are" strings.
In other languages, they would all implement "interface String", or
inherit from a pure virtual "String" base class, or something..
I think the naming makes sense, looked at this way, and since the naming
isn't going to change (for backwards compat reasons), lets choose to
look at it this way.
Other examples are #to_int and #to_ary.
I'd like to see the beginnings of a "Ruby Idiom Guide". String right now
is magical in how it inverts comparisons to allow things that have
#to_str to compare against itself. It isn't consistent. Fixnum seems to
do it whether #to_int is defined or not. Whats going on there?
$ irb
class One; def to_int; 1; end; def ==(other); 1 == other; end; end
=> nil
one = One.new
=> #<One:0x1d1584>
one == 1
=> true
1 == one
=> true
2 == one
=> false
one == 2
=> false
class Unity; def to_ary; [1,1]; end; def ==(other); [1,1] == other; end; end
=> nil
unity = Unity.new
=> #<Unity:0x33b1a0>
unity == [1,1]
=> true
[1,1] == unity
=> true
class OneX; def ==(other); 1 == other; end; end
=> nil
class UnityX; def ==(other); [1,1] == other; end; end
=> nil
onex = OneX.new
=> #<OneX:0x32290c>
unityx = UnityX.new
=> #<UnityX:0x31daec>
[1,1] == unityx
=> false
1 == onex
=> true
Huh? It always happens? I'll have to look into this more to figure out
whats going on... then submit docs.
Anyhow, I don't think it is common to implement this. But for
duck-typing to be consistent and pervasive we all have to, don't we?
So, for example, if I make a class that is a representation of a concept
of time that has a range past the unix time_t rollover (which kills
Time), and I want people to be able to use it where the use Time and
never know it's my own version, how I should do this needs to be
documented.
For example, I might decide that #to_tim is the way to indicate this (or
#to_time, if you prefer, don't get stuck on the name).
I think I should then override Time#===, #<=>, ... so that if +other+
isn't of class Time, but has a #to_tim method, it would call +other OP
self+.
Some folks talk about duck-typing like it magically happens, but it
doesn't, really, you have to make it happen. I should get
ProgrammingRuby2, see if this is covered there, I just haven't seen it
at a bookstore, yet. Guess I should just order, but I like to support
physical book stores.
Cheers,
Sam