In a language like Java or C# or Ada we can insist at
compile time that an argument conforms to a protocol,
whatever class it might be an instance of.

In Smalltalk, we can use #isKindOf: to test whether
an object inherits from a class, but that is often the
wrong test.�� We can use (multiple calls to) #respondsTo:
to tell whether an object conforms to a protocol.

The only snag, of course, is that in too many Smalltalk
systems, #respondsTo: is not trustworthy.�� If a class
has a method that sends #subclassResponsibility or
#shouldNotImplement, it's still counted as responding
to the selector in question.

This is not a problem in my Smalltalk because
(a) you are not allowed to create a direct instance of
a class where any method calls #subclassResponsibility.
(b) #shouldNotImplement appears only in test cases.
Since I already have named protocols, with classes
declaring their intention to conform to them, I've
been thinking about adding
�� aClass implements: aProtocol
�� anInstance conformsTo: aProtocol
but have not done that yet.

I note that Pharo V7.0.3 had 132 senders of #respondsTo:
and Pharo V8.0.0 has 126 senders of #respondsTo:.
These neatly bracket Dolphin 7's 130.



On Wed, 16 Sep 2020 at 06:50, St��phane Ducasse <stephane.ducasse@inria.fr> wrote:


On 14 Sep 2020, at 16:02, Roelof Wobben via Pharo-users <pharo-users@lists.pharo.org> wrote:


Thanks Richard for this explanation.
and I like also your idea of using #respondTo instead of asking a object if its a collection or a item.

refrain from using respondTo:
I make code difficult to evolve and can introduce vicious bugs.

S.��
Roelof


Op 14-9-2020 om 14:28 schreef Richard O'Keefe:
"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.

On Sun, 13 Sep 2020 at 21:26, Roelof Wobben via Pharo-users <pharo-users@lists.pharo.org> wrote:
Hello,

I know that OOP is not asking a object what it is but I have to flatten a array so I did this :

flattenArray: aCollection
������ ^ (OrderedCollection
������ ������ streamContents: [ :stream | self flatten: aCollection into: stream ])
������ ������ asArray

flatten: anObject into: result
    ^ anObject isCollection
        ifTrue: [ anObject do: [ :item | self flatten: item into: result ] ]
        ifFalse: [ anObject ifNotNil: [ result nextPut: anObject ] ]

The name flattenArray is given bij exercism. 

Now I wonder how I can make this more a OOP solution. 

Can someone give me some hints or some examples ?

Roelof



--------------------------------------------
St��phane Ducasse
03 59 35 87 52
Assistant: Aurore Dalle��
FAX 03 59 57 78 50
TEL 03 59 35 86 16
S. Ducasse - Inria
40, avenue Halley,��
Parc Scientifique de la Haute Borne, B��t.A, Park Plaza
Villeneuve d'Ascq 59650
France