|
Perhaps I was being naive but I never expected quite the chatter
that my post on HumaneInterface opened up. Sadly most of
it ended up being arguments about the relative merits of Ruby's
Array and Java's List rather than the underlying points I was trying
to make, but despite that I think some nice conversational
tributaries appeared. (Although I feel I ought to point out that it wasn't my intention
to say that I thought that Ruby's Array was better or indeed that
Ruby is better - I don't think either is better than the other
unless you give more context. As it turns out I like both Ruby's Array and
Java's List, although they are designed quite differently. Like any
software they are flawed, since nobody writes classes that are
exactly the way I want them this minute, but I wouldn't like to pit
any of my code against them. The point is they are both useful and I
use them both a lot - which is why they came to mind as an example.) One of these conversational threads brought out that there are
other reasons for the differences between Array and List than the
humane/minimal philosophies. One of these reasons has to do with the
way similar functionality plays different roles in the two
languages. Ruby's Array has a number of methods that made a few people
puzzled when the looked at the list. Push and pop - as Elliotte
said "Someone pushed a stack into the list". There's also shift and
unshift which are like a list. This doesn't look right - Elliotte
again "if you're using a queue or a stack, shouldn't you use a Queue or Stack class rather a List class?" Reading this triggered a thought in one of the recesses of my
memory. I dug out Smalltalk Best Practice Patterns, a fantastic book
that anyone who seriously wants to understand object-orientation
should read (despite the funny syntax).
"One of the first objects many people write when
they come to Smalltalk is Stack. Stack is the basic data structure,
fabled in song, story, and hundreds of papers about theoretical
programming languages... there is no Stack class in any of the basic
images. I've seen one written any number of times, but they never
seem to last long."
--Kent Beck
The smalltalker approach, at least then, was to use
OrderedCollection, Smalltalk's equivalent of Ruby's Array. There
wasn't even a push or pop - instead Kent showed using addLast: and removeLast:. Kent didn't give an explanation for the lack or a stack (and
queue) - "Why is there no Stack in Smalltalk? Well, 'just because'. It
is part of the culture to simulate stacks using OrderedCollection." I'm not sure how I feel about this (and I get the distinct
impression of uncertainty in Kent's writing). If you are going to use
something like a queue it does make sense to say Stack
new rather than OrderedCollection new, let alone
use push and pop rather than addLast and removeLast. It strikes me that part of this situation may be to do with the
difference between static and dynamic languages. Static languages like
to talk to objects through strict type interfaces, dynamic languages
have classes that can fit multiple roles - Duck Typing. Java
also has a list that does double duty as a queue: LinkedList,
but you'd typically use it through distinct interfaces not realizing
the common implementation. The Smalltalk feeling is that we can get
what we want with our OrderedCollection, so why build another class?
Ruby seems to be echoing that reaction and adding the meaningful
method names for people who use it in that context. (Although to be
fair I have no idea whether the rubyists actually are happy with Array
being a stack, or whether it's a piece of regretful legacy.) Another factor is what the language encourages for implementing
these structures. As Charles
Miller said "Java's design affords small interfaces, and
utility functions provided as static methods on helper classes. Ruby's
design affords larger classes with mixed-in utility methods." Perhaps one of the conclusions from this is that we should be
wary of judging the features of a class in one language using the
values of another language. Is Array the equivalent of List or of
List plus various interfaces and implementations in the collections
package - or is it something even more complicated? Some people
might recoil from the thought of doing 78 things to a list, but I
suspect lispers would think of many more to add. Ruby's Array has
it's warts, but I must admit I like working with it more than the
Java collections, although how much this is due to the humane
interface guidelines and how much due to Ruby syntactic support I'm
not sure. All in all I'm not sure who I agree with here, or whether it
really matters that much. Like with many of these arguments I think
the most interesting thing is to try to understand both points of
view.
|