"OOP is not asking an
object what it is"? You've lost me.
I'm reminded of a joke
exam question that goes something
like this:
Some things have
ping nature and other things have pong nature.
Discuss, with
examples.
Whatever else it is,
OOP is a means to an end, not an end in itself.
It's not a religion.
Allah will not cast you into the Fire for using
something which is not
ritually pure.
The whole point of the
Design Patterns movement was not to present
canned solutions but
to describe common *situations* characterised
by (metaphorical)
*forces* pushing you in incompatible directions.
Question 1: Why do you
even have a stream there?
flattenArray:
aCollection
|buffer|
buffer :=
OrderedCollection new: aCollection size.
self flattenArray:
aCollection into: buffer.
^buffer asArray
flattenArray: anObject
into: buffer
(anObject
respondsTo: #do:)
ifTrue:
[anObject do: [:each | self flattenArray: each into: buffer]
ifFalse:
[anObject ifNotNil: [buffer addLast: anObject].
(CAUTION: untested
code.)
Question 2: is there
any point in *trying* to make this more ping and less pong?
I have to say that in
40 years of programming, I have *never* wanted to flatten
a completely arbitrary
structure. When I have wanted to flatten something, it
has always been an
instance of the Composite design pattern, so that a specific
and quite small set of
classes has been involved.
I am well aware that
some Smalltalk systems have some sort of 'flatten'
lying around like a
rake in the grass, but I have found no two which agree
on the specification.
Question 3: Let's
consider an if-less alternative.
Stream
flattenInto: buffer
self do: [:each|
each flattenInto: buffer].
Collection
flattenInto: buffer
self do:[:each |
each flattenInto: buffer].
Object
flattenInto: buffer
buffer addLast:
self.
UndefinedObject
flattenInto: buffer
"Do nothing."
This is Smalltalk,
where we *can* add methods to system classes like these.
When the payoff is
worth it, I have no qualms whatever in doing so.
But putting methods of
little or no utility into the interface of EVERY
object just feels so
wrong.
Here we have opposing
forces:
- The first approach
adds two methods to your worker class,
and no methods to
any system class. Instead, it uses
"does this object
know how to iterate over its elements?"
and "is this object
nil?". This does minimal damage to
system structure at
the price of a little ritual impurity.
- The second approach
adds a method to four system classes,
enlarging the
interface of every object in the system,
creating a level of
coupling we'd be better without, and
making it harder
for someone reading your code to figure
out what's going
on.
In the context of a
Composite, with a limited number of
application classes
involved, the second approach is better;
the method is/methods
are not defined anywhere they should
not be.
In the context of
*this* problem, the first approach is
better. MUCH better.
Why? Because *encapsulation* is much
more important to OOP
than absence-of-IFs.