“Tim Hunter” cyclists@nc.rr.com writes:
Q: I’ve defined a class whose objects may be ordered. What should
my <=> method do when the “other” argument is not in the same
class?
A. Raise a TypeError exception.
I have to say I disagree with this fairly strongly.
The <=> method in most of Ruby’s
built-in classes will raise a TypeError exception if “other”
can’t be coerced into the same class.
There’s a boat load of difference between coercion and “being the same
class”. For example, following your code example would mean that
1 <=> 1.2
would raise a type error.
[…]
These are good points, Dave (and David Black as well), and I do not disagree,
but I will point out that the counter-examples given are strongly in the domain
of built-in classes (i.e. String <=> Regexp, Integer <=> Float), and this is no
surprise: the classes built in to the langauge are obviously designed to work
together to a degree.
The FAQ is about user-defined classes, and I’ll make the following points in
support of type-checking in the comparison operator:
- things that can be compared are generally data objects more than behaviour
objects
- it is behaviour objects that are capable of masquerading, so the points
raised by Davids would apply mostly to those
- user-defined data objects are generally quite application-, or domain-
specific
- application- or domain-specific objects are generally not designed to
be compared to built-ins or other user-defined objects [1]; obviously,
exceptions exist and this should be noted
- coercion between user-defined types is a rare thing, and the programmer
would obviously make use of it in comparison if it exists
- if the relationship between user-defined types is known (and it should be)
why shouldn’t it be encoded/enforced?
- the price of not checking the class of the object to be compared is
possibly calling methods that don’t exist, or that do the “wrong” thing
(e.g. consumed by method_missing)
- the benefit of checking the class of the object to be compared is clearer
error messages and prevention of doing The Wrong Thing
- the cost of checking the class of the object to be compared, after
considering all of the above, is … what?
Overzealously checking the class of parameters defeats much of the
point of Ruby.
Dave
To which I say “everything in moderation”. I perform class-checking on my
data-objects when I have considered all the above and conclude that there is no
good reason not to. Comparison seems like an important part of program logic,
and I like to catch errors early. Especially after modifying something -
comparison is something that happends “downstream”, nowhere near the actual
modification. Also, I like meaningful error messages where possible.
I also like Ruby’s flexibility, so I don’t overdo it, and take advantage of the
flexibility (at the risk of weird errors) when I can.
Cheers,
Gavin
PS. I don’t know what this means for the FAQ. A bit of discussion, I suppose.
[1] A user-defined data object would generally have several (N>2) fields.
Comparison with another object would generally involve most of these N fields.
Thus comparisons with built-in types (generally 1 field) are not meaningful
(again, exceptions exist, but they are exceptions). Also, a different
user-defined object would only compare meaningfully if it was known to be
related in some way.
···
From: “Dave Thomas” Dave@PragmaticProgrammer.com