On Thursday 29 May 2008 00:59:42 Mark W. wrote:
I must respectfully disagree. I learned OOP (in 1989) before C++ was
even hardly available on PCs, much less Java. The OOP language I
learned was an amalgam of Smalltalk and Lisp.
That’s interesting.
It’s my understanding that Ruby borrows its concept of “sending
messages” from
Smalltalk, which lets us do things like #send and #method_missing.
I can say
quite categorically, that in OOP, classes are ways to generalize. You
generalize based on characteristics and behaviors. A class is not
simply a random collection of methods. It would be rather useless if
class was unrelated to category.
I’m going to have to respectfully disagree here. Having done
prototype-based
development in JavaScript, as I understand it, it’s far easier to
implement a
class-based system on top of a prototype system than the other way
around.
In fact, I’ve seen it done, in various ways, with varying degrees of
success
and usability.
Unless you are going to have branching based on type – that is, simple
method
overloading (as in C++ and friends) – I don’t see as much point to a
rigid
type system.
It boils down to: Why should I care whether I’m being passed a number or
something which merely behaves like a number? Why should I care if I’m
being
passed a string or an array of characters?
Or even, why should I care if I’m being passed a real local object, or a
proxy
to a remote object? Check this out:
http://ruby-doc.org/core/classes/DRb/DRbObject.html
Now, for the simple case of a Numeric, we’re probably over-analyzing it.
There’s not a huge amount of potential for replacing it with something
Numeric-like that does the same job, and we can easily see where relying
on
to_i might (in VERY unlikely circumstances) give us something we don’t
want.
But I’m finding these remarks about “attititude” kind of amusing. It’s
like Ruby isn’t a tool, it’s a “mindset.” We don’t forgo something
like Numeric === v because it’s wrong (the OP in fact said it was
slightly more readable), but because Ruby has duck-typing,
Well, there is some truth to that – as an example, Ruby completely
lacks
anything resembling the C for loop. If that’s what you’re expecting, you
have
to build it out of a while loop:
i=0
while i < data.length
do_something_with data[i]
i += 1
end
There’s nothing wrong with that. But I hope most of us forgo it in
favor of:
data.each { |datum|
do_something_with datum
}
Which ends up being more readable, among other things.
It’s not absolute. There are cases where you want traditional looping
constructs instead of Ruby iterators, and there are cases you want
classes
instead of duck typing. But these are the exception, not the rule.
I won’t stop you from using Ruby if you’d rather build for loops. Maybe
you’ll
get better at it:
data.length.times { |i|
do_something_with data[i]
}
But if you do that, I don’t understand why you’re using Ruby. Again,
nothing
wrong with it – do whatever makes you happy, and maybe you’re right and
I’m
wrong. But I doubt I’ll ever understand it.
However, the use case
might be that any object with that method is fine and dandy. In that
case, I totally agree that checking for response to it is reasonable,
if not 100% reliable. But if we’re looking for Fixnums, Floats, and
other builtin classes, then checking again Numeric seems
straightforward.
Can you outline a few real-world examples, where it’s OK to get a
descendant
of Numeric, but not something which merely implements to_i or to_f?
If you want you know whether an object is in some category in an OO
way, you come up with a way to ask it.
True. And often the most straightforward and fundamental way to do
that is to call its #class method.
Not really.
Firstly, #class doesn’t provide any way to be in multiple categories.
Ruby
doesn’t support multiple inheritance.
Second, given no context, there’s not really any way I could override
class to
provide multiple membership. I’m either an Array or I’m a String. I
can’t be
both.
(Actually, I could probably pull something incredibly sneaky by
returning an
object which pretends to be a class, and returns true when compared to
other
classes on some list – but I think I’d have to override some methods in
Class and/or Module to make it bulletproof.)
Now, we could meet halfway. All Numerics define #integer?, which
responds True
for Integer and Bignum, and false for everything else. Object defines
#nil?,
which is true for NilClass and false for everything else. And, worst
case,
calling the object’s own #kind_of? method gives me a place to override
that
type check – I don’t believe that the Class === obj syntax allows that.
Their power is indeed to
categorize and generalize objects, which can be specialized with
inheritance (another old school concept, I suppose).
Inheritance can be approximated in Ruby with mixins. In JavaScript, it’s
actually possible to write mixin functionality from the ground up –
create a
new class, and define it as a collection of methods from selected other
classes, plus a new collection you define right here.
I’m not sure I know how to implement ad-hoc prototypes and things like
#define_method from pure inheritance semantics. I am sure I can create
inheritance out of pure prototype semantics.