One of the first files I looked at, lib/shoes.rb, opens right up with this interesting bit of interestingness:
class RangeOkay. So we're defining a
def rand
conv = (Integer === self.end && Integer === self.begin
? :to_i
: :to_f)
((Kernel.rand * (self.end - self.begin))
+ self.begin).send(conv)
end
end
rand()
method on the built-in Ruby class Range
, which will return a random value from within the begin
and end
values of the Range
. Neato. And apparently the use of conv
is meant to produce a result of a float or an integer, depending on the nature of the endpoints of the Range
. Again: neato. But I hadn't seen the use of the ===
operator in this context before. The docs and the Pickaxe book are a little obtuse on this, so I did some
irb
spelunking:>> r = (1..27)Hmm. So
=> 1..27
>> r.class
=> Range
>> r.begin
=> 1
>> r.begin.instance_of? Integer
=> false
>> r.begin.class
=> Fixnum
>> r.begin.kind_of? Fixnum
=> true
>> r.begin.kind_of? Integer
=> true
instance_of()
doesn't mean quite the same in Ruby as, say, the instanceof
operator in Java does. (That, or Fixnum
doesn't truly inherit from Integer
in Ruby.)Also, as it turns out:
>> Fixnum === r.beginSo it would seem that the
=> true
>> Integer === r.begin
=> true
[class] === [value]
syntax is syntactic sugar for [value].kind_of? [class]
It's the bit about:
>> r.begin.instance_of? Integerthat surprised me most, being the pathetic Java programmer that I am. And being that (according to the documentation for Integer on ruby-doc.org):
=> false
Apparently "is the basis for" != "is a superclass of".Integer
is the basis for the two concrete classes that hold
whole numbers,Bignum
andFixnum
.
Or is that "!==="...?
7 comments:
instance_of? doesn't return true for superclasses, but kind_of? does. They're different methods.
=== is also a method, and for Classes, and it's basically an alias for is_a?, which is an alias for kind_of?.
Sorry for the double post, but I forgot to mention something: === is used by the case expression no matter what the objects. In the case of a Class, like Fixnum, it's useful as an alias to kind_of? so you can do the following:
case obj # test obj's type
when Fixnum then treat_as_number(obj)
when String then treat_as_string(obj)
end
=== is actually pretty powerful and woefully underused. I'm actually writing some posts about using === in Ruby. Here's the first one: Unlocking The Power Of Case Equality: Proc#===
@avik das (first comment): Right. So it's not that I expected those two methods to do the same thing. I knew about instance_of? and expected it to do the same thing as Java's instanceof. I didn't know about kind_of? at all.
My fault, I know, for thinking like a Java programmer. This is exactly why I'm making myself read more idiomatic Ruby.
@david
Actually, it wasn't until reading your post that I thought about those methods and their differences. For all my Ruby programming days, I've been using is_a?.
But it's the case statement that's an especially powerful use of ===.
Yeah -- according to the docs is_a? is an alias for kind_of? (or the other way around, I guess). I'd forgotten about that one too.
@farrel: Interesting stuff. I'll look forward to the other installments in the series.
Post a Comment