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.duca...@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
> http://stephane.ducasse.free.fr / http://www.pharo.org
> 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
>
>

Reply via email to