N
Nathan Weston
The latest Perl exegesis
(http://www.perl.com/pub/a/2003/07/29/exegesis6.html?page=4)
introduces "junction types", which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.
So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:
# 1 == any(1,2,3)
true
# 4 == any(1,2,3)
false
And all was well. But then I hit a snag:
# 1 < any(1,2,3)
ERR: (eval):1:in `<': Disjunction can't be coerced into Fixnum
Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).
Of course, with ObjectSpace and module_eval, I can redefine everyone's
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.
Is there a better way to do this?
If there's not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:
class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don't know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me --
#let's give them a chance
return (obj == self)
end
end
end
Or at least, that's the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other --
either by returning false or throwing an exception.
If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn't know
anything about Junctions would just let the Junction do the
comparison.
(http://www.perl.com/pub/a/2003/07/29/exegesis6.html?page=4)
introduces "junction types", which are really cool.
In short, you can do expressions like (a == any(1,2,3)) or (a >
all(1,2,3)) instead of (a == 1) or (a == 2) or (a == 3), etc.
So of course, I immediately set out to do this in ruby. So, I whipped
up a Disjunction class, and the any() function for syntactic sugar,
and soon I could do:
# 1 == any(1,2,3)
true
# 4 == any(1,2,3)
false
And all was well. But then I hit a snag:
# 1 < any(1,2,3)
ERR: (eval):1:in `<': Disjunction can't be coerced into Fixnum
Fixnum#== seems to be smart enough to call Disjunction#==, which gets
the behavior I want. Unfortunately, Fixnum#< is not, and neither are
most of the <,>,== methods in the various built-in classes (i.e.
String#== and Array#== both return false for any Junction class).
Of course, with ObjectSpace and module_eval, I can redefine everyone's
comparison methods to work properly, but this is kind of ugly. Also,
if someone defines a new class after after I have done my ObjectSpace
hack, they have to explicitly write their comparison methods to know
about Junctions.
Is there a better way to do this?
If there's not a better way, should there be?
I was thinking that perhaps all comparison methods should have a
similar semantics, along the lines of:
class Foo
def ==(obj)
if obj.is_a?(Foo)
#I know how to compare myself to other Foo objects,
#so I will do so
return somevalue
else
#I don't know how to compare myself to non-Foo objects,
#but maybe they know how to compare themselves to me --
#let's give them a chance
return (obj == self)
end
end
end
Or at least, that's the basic idea. There also needs to be some way to
bail out when neither class knows how to compare to the other --
either by returning false or throwing an exception.
If all comparison methods worked this way, I could implement my
Junction classes with no hacks, since objects that didn't know
anything about Junctions would just let the Junction do the
comparison.