Object>>#is:? (was: Re: PackageDependencyTest)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
71 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
Le 04/03/2010 21:42, Juan Vuletich a écrit :

> Stéphane Rollandin wrote:
>>
>> ...
>> let's now consider MySpecializedMorph, a subclass of MyMorph that I
>> *do not* want to be considered as MyMorph:
>>
>> is: aSymbol
>>      (super is: aSymbol and: [aSymbol =~ #MyMorph])
>>          or: [aSymbol == #MySpecializedMorph]) ifTrue: [^ true].
>>      ^ false
>>
>> see the problem ?
>
> Yes, I see it. As I see it, #is: is for asking about conformance to a
> certain protocol. And your MySpecializedMorph does know what protocols
> it conforms. So it can implement something like:
>
> is: aSymbol
>      aSymbol == #Morph ifTrue: [^true].
>      aSymbol == #MySpecializedMorph ifTrue: [^true].
>      ^false

ok; but then if we want to add another protocol true for all Morphs, we
will have to go back to MySpecializedMorph>>#is: to add it there. as I
say in another parallel message, if this new protocol belongs to another
package, that makes #is: an immediate source of conflict between packages.

#is: becomes an attractor, a fixed point for all protocols, dispatched
on all classes and having to support all packages. it's another form of
the God class: it's the God method for protocols. this is not OOP as I
understand (and practice) it.

regards,

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Juan Vuletich-4
In reply to this post by Stéphane Rollandin
Stéphane Rollandin wrote:
>> I really fail to see how #is: is complex and messy. Really.
>
> well for one thing all #is:-type of attributes have to be centralized
> in one place, the #is: method.

That's actually the good part. You have all the answers to is: aProtocol
in one place. Thats good, not messy.

> a Morph that isMorph, isBeautiful and isWhatMyUncleLikes has to
> provide the three answers to very different questions in the same
> place. Now if another package needs to know if a Morph isMyCupOfTea,
> it must override aMorph>>#is:

I'd strongly suggest doing some new morph classes that can be your cup
of tea. And just implement #is: in those. I that way, Morph does not
need to know at all what a cup of tea is.

> so #is: can not actually safely belong to a single package. while
> #isWhatMyUncleLikes will only be in my package MyUncle, except if
> someone else has the same kind of weird ideas about protocol names.

Same as before. The only classes that should ever know about the concept
of what your uncle likes are those in package MyUncle. The current
implementation in Morph is perfectly good for that. If used properly,
this actually decreases the need for overrides. No method in Morph, in
any package, should know about your uncle or your cup of tea.

> plus, looking for the senders of #isBeautiful immediately gives me all
> classes responding to the protocol. with the #is: idea, all protocols
> are mangled in one: you have to look at all #is: implementations, in
> all objects (!) to see where you protocol went. if that's not messy,
> call me Joséphine.

I guess you meant 'implementors' and not 'senders'. Anyway, with #is:
you just ask for senders of #Beautiful and you get an exact answer,
without any spurious classes answering false.

Cheers,
Juan Vuletich

> regards,
>
> Stef
>

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
In reply to this post by Michael Haupt-3
> all right, I just looked at your problem once more, and believe it's
> abusive. An inheritance that is not an is-a relationship induces
> physical pain in this simple me. :-) So I guess the problem is
> actually somewhere else.

well we have to know if #is: is about testing inheritance, or more
generally protocols. if it's for testing inheritance, all right my
problem is not pertinent and I have no issues with #is: (only that it's
maybe a little too much to call this #is:, then; it could be called
#isSortOf: :)

best,

Stef






Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Igor Stasenko
In reply to this post by Stéphane Rollandin
2010/3/4 Stéphane Rollandin <[hidden email]>:
>> I really fail to see how #is: is complex and messy. Really.
>
> well for one thing all #is:-type of attributes have to be centralized in one
> place, the #is: method.
>
> a Morph that isMorph, isBeautiful and isWhatMyUncleLikes has to provide the
> three answers to very different questions in the same place. Now if another
> package needs to know if a Morph isMyCupOfTea, it must override aMorph>>#is:
>
why Morph should ever care about answering to isBeatiful or isWhatMyUncleLikes ?
isMorph is enough.

If your object supports multiple aspects , like
 #isApple
and
 #isFruit
then i'd expect to have a single class for every single aspect.

> so #is: can not actually safely belong to a single package. while
> #isWhatMyUncleLikes will only be in my package MyUncle, except if someone
> else has the same kind of weird ideas about protocol names.
>
ah yeah! And to achieve this, you need to patch an Object class by
adding #isWhatMyUncleLikes.
But Object really does not belongs to your package.

> plus, looking for the senders of #isBeautiful immediately gives me all
> classes responding to the protocol. with the #is: idea, all protocols are
> mangled in one: you have to look at all #is: implementations, in all objects
> (!) to see where you protocol went. if that's not messy, call me Joséphine.
>
No. Things remain same, if you will use #is: in a way, how Juan using it

is: aSymbol
  ^ aSymbol == #myUniqueAspect ifFalse: [ super is: aSymbol ]

if you browse all senders of #myUniqueAspect, you will easily find this method.

Btw, i'm also think that adding #isKindOf: to base class is an overkill.


> regards,
>
> Stef
>
>
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

keith1y
In reply to this post by Bert Freudenberg

> perform:ifAbsent:

Indeed,

I also think that the split/join discussion needs to happen again. I  
thought we had done this to death before, but up pops another solution  
from nowhere.

http://bugs.squeak.org/view.php?id=4874

Keith

Reply | Threaded
Open this post in threaded view
|

Boolean expressions (was: Re: [squeak-dev] Re: Object>>#is:? (was: Re: PackageDependencyTest))

Levente Uzonyi-2
In reply to this post by Juan Vuletich-4
On Thu, 4 Mar 2010, Juan Vuletich wrote:

> Stéphane Rollandin wrote:
>>
>> ...
>> let's now consider MySpecializedMorph, a subclass of MyMorph that I *do
>> not* want to be considered as MyMorph:
>>
>> is: aSymbol
>>     (super is: aSymbol and: [aSymbol =~ #MyMorph])
>>         or: [aSymbol == #MySpecializedMorph]) ifTrue: [^ true].
>>     ^ false
>>
>> see the problem ?
>
> Yes, I see it. As I see it, #is: is for asking about conformance to a certain
> protocol. And your MySpecializedMorph does know what protocols it conforms.
> So it can implement something like:
>
> is: aSymbol
>   aSymbol == #Morph ifTrue: [^true].
>   aSymbol == #MySpecializedMorph ifTrue: [^true].
>   ^false
I don't get you guys, why do these expressions have to be so
complicated? Just compare this with those above:

is: aSymbol

  ^aSymbol == #Morph or: [ aSymbol == #MySpecializedMorph ]

If you have a lot of protocols you can use the super fast
primitive supported #pointsTo: and have a lot cleaner (and possibly
faster) code:

is: aSymbol

  ^#(Morph MySpecializedMorph FooMorph BarMorph) pointsTo: aSymbol


Levente

>
> without calling super. Please not that in Cuis, #is: does not call #isKindOf:
> at all.
>
> Cheers,
> Juan Vuletich
>
>> I have to be aware of the behavior of each implementation of #is: in the
>> upward inheritance chain if I want to produce the proper tests. Going down,
>> those tests will become more and more complex and hard to grok. Plus,
>> reimplementing any of the #is: can possibly break any of the #is: in
>> subclasses. So all #is: implementations in a given hierarchy are actually
>> dependent. It's pure spaghetti code, as far away from OOP as it gets.
>>
>> I guess I'm missing something. how is this supposed to work ?
>>
>> Stef
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Juan Vuletich-4
In reply to this post by Stéphane Rollandin
Stéphane Rollandin wrote:

> Le 04/03/2010 21:42, Juan Vuletich a écrit :
>> Stéphane Rollandin wrote:
>>>
>>> ...
>>> let's now consider MySpecializedMorph, a subclass of MyMorph that I
>>> *do not* want to be considered as MyMorph:
>>>
>>> is: aSymbol
>>>      (super is: aSymbol and: [aSymbol =~ #MyMorph])
>>>          or: [aSymbol == #MySpecializedMorph]) ifTrue: [^ true].
>>>      ^ false
>>>
>>> see the problem ?
>>
>> Yes, I see it. As I see it, #is: is for asking about conformance to a
>> certain protocol. And your MySpecializedMorph does know what protocols
>> it conforms. So it can implement something like:
>>
>> is: aSymbol
>>      aSymbol == #Morph ifTrue: [^true].
>>      aSymbol == #MySpecializedMorph ifTrue: [^true].
>>      ^false
>
> ok; but then if we want to add another protocol true for all Morphs,
> we will have to go back to MySpecializedMorph>>#is: to add it there.

Yes. However, as others said, making a subclass that does not follow the
is-a rule is a bad idea. It will need to have special care with
inherited stuff in many places, not just #is: .

> as I say in another parallel message, if this new protocol belongs to
> another package, that makes #is: an immediate source of conflict
> between packages.

In my opinion, overrides should be forbidden for this very reason. But
that's another discussion. And having to use inheritance properly is the
smallest inconvenience of doing it.

>
> #is: becomes an attractor, a fixed point for all protocols, dispatched
> on all classes and having to support all packages. it's another form
> of the God class: it's the God method for protocols. this is not OOP
> as I understand (and practice) it.
>
> regards,
>
> Stef

Cheers,
Juan Vuletich

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
In reply to this post by Juan Vuletich-4
> Same as before. The only classes that should ever know about the concept
> of what your uncle likes are those in package MyUncle. The current
> implementation in Morph is perfectly good for that. If used properly,
> this actually decreases the need for overrides. No method in Morph, in
> any package, should know about your uncle or your cup of tea.

Ok, I see. We actually have different ideas about software design :)

That's ok, then. If there is a consensus that good Smalltalk design is
like you say (extension methods should be avoided, etc.) then I have
nothing to object. I will just continue silently in my own, parallel style.


> I guess you meant 'implementors'

yes :)

> you just ask for senders of #Beautiful and you get an exact answer,
> without any spurious classes answering false.

hmm.. by doing this you just load the mere presence of a Symbol in a
method source with a new semantic charge. I don't like this very much...
but again, it's a matter of taste in design.

best,

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Boolean expressions (was: Re: [squeak-dev] Re: Object>>#is:? (was: Re: PackageDependencyTest))

Juan Vuletich-4
In reply to this post by Levente Uzonyi-2
Levente Uzonyi wrote:

> On Thu, 4 Mar 2010, Juan Vuletich wrote:
>
>> Stéphane Rollandin wrote:
>>>
>>> ...
>>> let's now consider MySpecializedMorph, a subclass of MyMorph that I
>>> *do not* want to be considered as MyMorph:
>>>
>>> is: aSymbol
>>>     (super is: aSymbol and: [aSymbol =~ #MyMorph])
>>>         or: [aSymbol == #MySpecializedMorph]) ifTrue: [^ true].
>>>     ^ false
>>>
>>> see the problem ?
>>
>> Yes, I see it. As I see it, #is: is for asking about conformance to a
>> certain protocol. And your MySpecializedMorph does know what
>> protocols it conforms. So it can implement something like:
>>
>> is: aSymbol
>>   aSymbol == #Morph ifTrue: [^true].
>>   aSymbol == #MySpecializedMorph ifTrue: [^true].
>>   ^false
>
> I don't get you guys, why do these expressions have to be so
> complicated? Just compare this with those above:
>
> is: aSymbol
>
>     ^aSymbol == #Morph or: [ aSymbol == #MySpecializedMorph ]
>
> If you have a lot of protocols you can use the super fast primitive
> supported #pointsTo: and have a lot cleaner (and possibly faster) code:
>
> is: aSymbol
>
>     ^#(Morph MySpecializedMorph FooMorph BarMorph) pointsTo: aSymbol
>
>
> Levente

Oh! #pointsTo: ! Sweet!

Cheers,
Juan Vuletich

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Bert Freudenberg
In reply to this post by Michael Haupt-3
On 04.03.2010, at 21:42, Michael Haupt wrote:
>
> Stéphane,
>
> 2010/3/4 Stéphane Rollandin <[hidden email]>:
>> If #is: implementation has to reflect a class hierarchy, then I don't see
>> how it can be any better than #isKindOf: and #isMemberOf:
>
> #isKindOf: accepts a Class, while #is: accepts a Symbol. Helps decoupling.

Agreed, though that should be separate from #is: which had the idea of being about protocols, not class membership/inheritance.

How about having both:

#isA: will take a class name symbol, implementation like Andreas proposed based on #isKindOf:

#is: will take a symbol not directly related to a class, implemented and used as in Cuis

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
In reply to this post by Igor Stasenko
>> so #is: can not actually safely belong to a single package. while
>> #isWhatMyUncleLikes will only be in my package MyUncle, except if someone
>> else has the same kind of weird ideas about protocol names.
>>
> ah yeah! And to achieve this, you need to patch an Object class by
> adding #isWhatMyUncleLikes.
> But Object really does not belongs to your package.

I got it; see my answer to Juan. I guess I'm just programming in bad
style: I do indeed consider that Object is part of my packages (or, more
accurately, that Object is not a forbidden place for my package to go in).

The pleasure I have in programming Squeak comes largely from the fact
that I can dig code all other the place and tweak whatever class I want.
I need first to understand what a class is, what it does, then I have to
respect the way it is used in the image, but then, when I'm confident
enough that I am not behaving like a rude person, I feel free to add my
own code to it. That's my style.

regards,

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Boolean expressions (was: Re: [squeak-dev] Re: Object>>#is:? (was: Re: PackageDependencyTest))

Stéphane Rollandin
In reply to this post by Levente Uzonyi-2
> If you have a lot of protocols you can use the super fast
> primitive supported #pointsTo: and have a lot cleaner (and possibly
> faster) code:
>
> is: aSymbol
>
>   ^#(Morph MySpecializedMorph FooMorph BarMorph) pointsTo: aSymbol
>


wow. thanks for the pointer, I wasn't aware of this one :)

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Boolean expressions (was: Re: [squeak-dev] Re: Object>>#is:? (was: Re: PackageDependencyTest))

Bert Freudenberg
On 04.03.2010, at 22:21, Stéphane Rollandin wrote:

>
>> If you have a lot of protocols you can use the super fast
>> primitive supported #pointsTo: and have a lot cleaner (and possibly
>> faster) code:
>>
>> is: aSymbol
>>
>>   ^#(Morph MySpecializedMorph FooMorph BarMorph) pointsTo: aSymbol
>>
>
>
> wow. thanks for the pointer, I wasn't aware of this one :)
>
> Stef

It's also less readable. If you replace #pointsTo: with #includes: I know right away what it means. If you use this low-level optimization I have to think twice which object points where.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Juan Vuletich-4
In reply to this post by Stéphane Rollandin
Stéphane Rollandin wrote:

>> Same as before. The only classes that should ever know about the concept
>> of what your uncle likes are those in package MyUncle. The current
>> implementation in Morph is perfectly good for that. If used properly,
>> this actually decreases the need for overrides. No method in Morph, in
>> any package, should know about your uncle or your cup of tea.
>
> Ok, I see. We actually have different ideas about software design :)
>
> That's ok, then. If there is a consensus that good Smalltalk design is
> like you say (extension methods should be avoided, etc.) then I have
> nothing to object. I will just continue silently in my own, parallel
> style.

Well, I don't know if there is any consensus. After all, it is a pretty
new idea AFAIK and I'm the only one who actually used it. I'm just
describing a style that I like, and that works for me. Maybe a consensus
starts to be built after this discussion.

>> I guess you meant 'implementors'
>
> yes :)
>
>> you just ask for senders of #Beautiful and you get an exact answer,
>> without any spurious classes answering false.
>
> hmm.. by doing this you just load the mere presence of a Symbol in a
> method source with a new semantic charge. I don't like this very
> much... but again, it's a matter of taste in design.
>
> best,
>
> Stef

You can check a bit the symbols in Cuis implementors of #is: and senders
of them. Maybe you like it.

Using senders to find methods having to do with symbols that mean, for
example, a possible aspect or status of some object, is a pretty
standard practice. See for example senders of
#messageCategorySelectionChanged, #errorOnStep, #doesButtonAction. Of
course, the symbol being there is not enough. You also need to read the
code.

Cheers,
Juan Vuletich

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
> Using senders to find methods having to do with symbols that mean, for
> example, a possible aspect or status of some object, is a pretty
> standard practice. See for example senders of
> #messageCategorySelectionChanged, #errorOnStep, #doesButtonAction. Of
> course, the symbol being there is not enough. You also need to read the
> code.

I actually use this to find function senders in my lisp code (see
http://www.zogotounga.net/comp/squeak/lispkit.htm for details).
example:


ULisp>>slibIntegration

        "transparently using SLIB"

        ^#(in-library slib-integration

(defun display-source (symbol)
        'Display the source code for the procedure bound to SYMBOL
This can be either Lisp or Smalltalk code'
        (let ((proc (symbol-function symbol)))
                (if (#'primitive?' symbol)
                                (display (procedure-source proc))
                        (require `pretty-print)
                        (pretty-print (procedure-source proc)))))
               
)


the above code can be seen as a smart trick, or as a real ugly abusive
hack. depends on taste, again :)

Stef



Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Michael Haupt-3
In reply to this post by Stéphane Rollandin
Hi,

2010/3/4 Stéphane Rollandin <[hidden email]>:
> well we have to know if #is: is about testing inheritance, or more generally
> protocols. if it's for testing inheritance, all right my problem is not
> pertinent and I have no issues with #is: (only that it's maybe a little too
> much to call this #is:, then; it could be called #isSortOf: :)

#isA:? (OK, this makes complete sense for inheritance only.)

Best,

Michael

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
> #isA:? (OK, this makes complete sense for inheritance only.)

yes, for inheritance, #isA: is a good one IMO.


Stef



Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Michael Haupt-3
In reply to this post by Bert Freudenberg
Hi Bert,

On Thu, Mar 4, 2010 at 10:16 PM, Bert Freudenberg <[hidden email]> wrote:
> Agreed, though that should be separate from #is: which had the idea of being about protocols, not class membership/inheritance.

got it.

> How about having both: ...

Hm. Sounds sensible ... but slightly complicates the interface. That
said, if protocol dictates that #isA: is a partial function of #is:
(forgive incorrect terminology, please), it might turn out as
well-behaved.

Best,

Michael

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Michael Haupt-3
In reply to this post by Stéphane Rollandin
Hi,

2010/3/4 Stéphane Rollandin <[hidden email]>:
> That's my style.

http://gbracha.blogspot.com/2008/03/monkey-patching.html ;-) ;-) ;-)

scnr,

Michael

Reply | Threaded
Open this post in threaded view
|

Re: Object>>#is:? (was: Re: PackageDependencyTest)

Stéphane Rollandin
In reply to this post by Igor Stasenko
> Then, please , give me a concrete example, where you will have 3 classes,
> answering to isXXX message differently:
>
> base (false) ->  parent(true) ->  subclass(false).

I have this mostly in class-side methods; an example in Squeak proper
(that is, not my code), is TestCase class>>isAbstract

Stef



1234