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 |
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 > |
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 |
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. |
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 |
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 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 > > |
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 |
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 |
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 |
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 - |
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 |
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 |
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 - |
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 |
> 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 |
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 |
> #isA:? (OK, this makes complete sense for inheritance only.)
yes, for inheritance, #isA: is a good one IMO. Stef |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |