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 > >