Yes, it’s time for another Symbol trick!
class Symbol
def ===(obj)
obj.respond_to? “to_#{self}”
end
end
case “foo”
when :int then “integer”
when :str then “string”
when :ary then “array”
end #=> “string”
Genius. Sheer genius.
Daniel
Yes, it’s time for another Symbol trick!
class Symbol
def ===(obj)
obj.respond_to? “to_#{self}”
end
end
case “foo”
when :int then “integer”
when :str then “string”
when :ary then “array”
end #=> “string”
Genius. Sheer genius.
Daniel
On 7/27/06, Daniel S. [email protected] wrote:
Yes, it’s time for another Symbol trick!
class Symbol
def ===(obj)
obj.respond_to? “to_#{self}”
end
end
This idea has been discussed on this list before; I can’t find the
thread at the moment.
This seems like a really clever idea, and is fine for just playing
around… but it’s not advisable for general use. You’re changing the
semantics of Symbol#===, which will break things like this:
case method_name
when :reverse
#…
when :each
#…
else #…
end
The following is a simplified extract of what I use in Reg for a
similar feature. It’s safer, as long as nothing else decides to do
something with Symbol#[email protected]
class Symbol
def [email protected]; Reg::Knows.new(self) end
end
module Reg
class Knows
def initialize(sym)
@sym=sym
end
def ===(other)
other.respond_to? @sym
end
end
end
(You’re prepending “to_” to your method names before checking; I don’t
know why. This way seems more general…)
Caleb C. wrote:
thread at the moment.
end
Yes, that’s true – I only ever intended it to be a trick.
(You’re prepending “to_” to your method names before checking; I don’t
know why. This way seems more general…)
I was using it to demonstrate how you could duck type check with a case
statement, so focusing on the “type” made sense. I see this all the
time:
case obj
when Integer then foo
when String then bar
end
and it strikes me as not being very duckish (quacky?) Using if
statements can be annoying:
if obj.respond_to? :to_str
foo
elsif obj.respond_to? :to_int
bar
end
Maybe this would work?
class Symbol
def ===(obj)
return true if self == obj
obj.respond_to? “to_#{self}”
end
end
though something like this may cause trouble:
obj = :int
case obj
when :int then “integer”
when :str then “string”
end
Cheers,
Daniel
On 7/27/06, Daniel S. [email protected] wrote:
and it strikes me as not being very duckish (quacky?) Using if
statements can be annoying:if obj.respond_to? :to_str
foo
elsif obj.respond_to? :to_int
bar
end
I see where you’re coming from, but I guess I just don’t see that
#to_* methods as being that special. Why wouldn’t you want to do this
kind of dispatch for other methods too?
Using the code I posted previously, the above conditionals could be
written as:
case obj
when -:to_str
foo
when -:to_int
bar
end
I like that one best.
Fooling with the existing Symbol#=== in any way is very likely to
break some existing libs which assumes the current definition always
obtains… my way lets you use (almost-)symbols in the way you want to
use them. It is incompatible with libs that also define Symbol#[email protected] in a
different way, but those are presumably much rarer, perhaps
nonexistant. (Nobody’s as crazy as I am.) If you really want this
feature in a general way, (and I do, for Reg) this seems to be the
best compromise.
Because I only think the #to_x methods are directly related to types.
They even have more nuances than class-based types; there’s a difference
between defining #to_s and defining #to_str, for example.
In the spirit of making sure I understand, and perhaps explaining this
to anyone else that may be confused, the difference in these two kinds
of methods:
If an object can be represented as an integer in some cases (e.g. a
string, which could be set to something like “12”), it implements
to_i.
If an object is a natural representation of an integer, (like roman
numerals, as the example the Pickaxe gives), it implements to_int.
So this makes sense, though nothing about the naming convention of
these methods makes this particularly clear. However, this brings up
the question: If something acts exactly like an integer method-wise,
whats the benefit of explicitly calling to_int? This seems like a non
duck-typey thing to do.
Aleks
On Sat, 29 Jul 2006, Aleks Kissinger wrote:
So this makes sense, though nothing about the naming convention of these
methods makes this particularly clear. However, this brings up the
question: If something acts exactly like an integer method-wise, whats the
benefit of explicitly calling to_int? This seems like a non duck-typey
thing to do.
it might be faster to actually have an int
you can fail early by filtering on one ‘category’ of behaviours
guaranteed
by having an object respond_to? ‘to_int’, this is not unlike type or
interface checking
-a
Caleb C. wrote:
end
I see where you’re coming from, but I guess I just don’t see that
#to_* methods as being that special. Why wouldn’t you want to do this
kind of dispatch for other methods too?
Because I only think the #to_x methods are directly related to types.
They even have more nuances than class-based types; there’s a difference
between defining #to_s and defining #to_str, for example.
I like that one best.
Fooling with the existing Symbol#=== in any way is very likely to
break some existing libs which assumes the current definition always
obtains… my way lets you use (almost-)symbols in the way you want to
use them. It is incompatible with libs that also define Symbol#[email protected] in a
different way, but those are presumably much rarer, perhaps
nonexistant. (Nobody’s as crazy as I am.) If you really want this
feature in a general way, (and I do, for Reg) this seems to be the
best compromise.
Yes, I’ve adopted your solution; it is indeed the best way to get around
the problem.
This isn’t something I believe should go into core or anything, I just
think it’s a great showcase of Ruby’s flexibility.
Cheers,
Daniel
That makes sense. Thanks.
Aleks Kissinger wrote:
If an object can be represented as an integer in some cases (e.g. a
string, which could be set to something like “12”), it implements
to_i.If an object is a natural representation of an integer, (like roman
numerals, as the example the Pickaxe gives), it implements to_int.
That very nicely sums it up!
So this makes sense, though nothing about the naming convention of
these methods makes this particularly clear. However, this brings up
the question: If something acts exactly like an integer method-wise,
whats the benefit of explicitly calling to_int? This seems like a non
duck-typey thing to do.
In the example with the roman numerals, you might not want to implement
all the behavior of Numeric or Fixnum – it would make your class
unnecessarily complex. Rather just have a #to_int method that returned a
normal integer, be that a Fixnum or another object responded to the same
methods. In many cases, you have to return a Fixnum, or some methods
will complain.
This approach means that you can give your roman numeral objects
directly as arguments to methods. If they call #to_int on the object
before dealing with it, it’ll behave just as if it’s a Fixnum.
def double(num)
num.to_int * 2
end
double(roman_num)
Cheers,
Daniel
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.
Sponsor our Newsletter | Privacy Policy | Terms of Service | Remote Ruby Jobs