Andreas wrote:
> (foo isKindOf: FooBarMorph) ifTrue:[...] > > is completely pointless. If you're writing this already, you might as well > avoid that dependency and write: > > (foo is: #FooBarMorph) ifTrue:[...] > > etc. I'd really like to see #is: integrated so that it can used > interchangeably with #isKindOf: but using the name instead of the type. That would be a great method for helping to avoid hard dependencies. My only suggestion would be for us to consider the namespace. It might be a shame to consume beautifully terse #is: for something as mundane as a package-existence / type-check. Applications might already, or want to, use #is:. However, any overrides of #is: will rob them of the functionality provided by Object>>#is:, so a complication is introduced, a choice is forced. Ok, I might be wrong in a practical-sense about this, since the package-existence check would typically be on a PackageInfo object or something that probably wouldn't otherwise need #is:. My only point is that, we should remember to duly consider the namespace when consuming a selector as grand as #is: in case it might be better-appreciated in the application namespace.. Regards, Chris |
For discussion, this is what I'm suggesting:
Object>>is: aSymbol "A generic membership test. Should be used to avoid the proliferation of isXXX methods where appropriate. Use it like here: FooBar>>is: aSymbol ^aSymbol == #Foo or:[aSymbol == #Bar or:[super is: aSymbol]] This implementation can also be used with class names to replace the usage of aMorph isKindOf: SketchEditorMorph with, e.g., aMorph is: #SketchEditorMorph to avoid unnecessary dependencies on classes" "Check to see if aSymbol is a class name in the receiver's environment" self class environment at: aSymbol ifPresent:[:aClass| ^self isKindOf: aClass]. ^false On 3/4/2010 10:50 AM, Chris Muller wrote: > Andreas wrote: > >> (foo isKindOf: FooBarMorph) ifTrue:[...] >> >> is completely pointless. If you're writing this already, you might as well >> avoid that dependency and write: >> >> (foo is: #FooBarMorph) ifTrue:[...] >> >> etc. I'd really like to see #is: integrated so that it can used >> interchangeably with #isKindOf: but using the name instead of the type. > > That would be a great method for helping to avoid hard dependencies. > My only suggestion would be for us to consider the namespace. It > might be a shame to consume beautifully terse #is: for something as > mundane as a package-existence / type-check. > > Applications might already, or want to, use #is:. However, any > overrides of #is: will rob them of the functionality provided by > Object>>#is:, so a complication is introduced, a choice is forced. > > Ok, I might be wrong in a practical-sense about this, since the > package-existence check would typically be on a PackageInfo object or > something that probably wouldn't otherwise need #is:. > > My only point is that, we should remember to duly consider the > namespace when consuming a selector as grand as #is: in case it might > be better-appreciated in the application namespace.. > > Regards, > Chris > > |
Hi,
Am 04.03.2010 um 19:58 schrieb Andreas Raab <[hidden email]>: > For discussion, this is what I'm suggesting: > > Object>>is: aSymbol > > "A generic membership test. Should be used to avoid the > proliferation of isXXX > methods where appropriate. Use it like here: > > FooBar>>is: aSymbol > ^aSymbol == #Foo or:[aSymbol == #Bar or:[super is: > aSymbol]] > > This implementation can also be used with class names to replace > the usage > of aMorph isKindOf: SketchEditorMorph with, e.g., aMorph is: > #SketchEditorMorph > to avoid unnecessary dependencies on classes" > > "Check to see if aSymbol is a class name in the receiver's > environment" > self class environment > at: aSymbol > ifPresent:[:aClass| ^self isKindOf: aClass]. > > ^false I like it. We've frequently had hard times explaining to students why monkey patching is (used to be?) somewhat idiomatic in Squeak. Good to have this, it does away with one particular awkwardness and thus makes Squeak a little bit easier to grasp. Best, Michael |
In reply to this post by Andreas.Raab
Another way of doing this, (last seen in SmalltalkAgents) is to
implement askFor: anObject askFor: #isMorph. We had an ongoing debate on mantis as to whether this should return nil or false by default. (I prefer false, my more purist friends appear to prefer nil) if the selector is not implemented. I would favour this approach because askFor: is useful for other purposes, and in a world where things are more modular and less tightly coupled, it can be useful to have askFor: and askFor: aSelector ifAbsent: Keith so that the traditional isXX selectors still work, but > For discussion, this is what I'm suggesting: > > Object>>is: aSymbol > > "A generic membership test. Should be used to avoid the > proliferation of isXXX > methods where appropriate. Use it like here: > > FooBar>>is: aSymbol > ^aSymbol == #Foo or:[aSymbol == #Bar or:[super is: aSymbol]] > > This implementation can also be used with class names to replace > the usage > of aMorph isKindOf: SketchEditorMorph with, e.g., aMorph is: > #SketchEditorMorph > to avoid unnecessary dependencies on classes" > > "Check to see if aSymbol is a class name in the receiver's > environment" > self class environment > at: aSymbol > ifPresent:[:aClass| ^self isKindOf: aClass]. > > ^false > > > On 3/4/2010 10:50 AM, Chris Muller wrote: >> Andreas wrote: >> >>> (foo isKindOf: FooBarMorph) ifTrue:[...] >>> >>> is completely pointless. If you're writing this already, you might >>> as well >>> avoid that dependency and write: >>> >>> (foo is: #FooBarMorph) ifTrue:[...] >>> >>> etc. I'd really like to see #is: integrated so that it can used >>> interchangeably with #isKindOf: but using the name instead of the >>> type. >> >> That would be a great method for helping to avoid hard dependencies. >> My only suggestion would be for us to consider the namespace. It >> might be a shame to consume beautifully terse #is: for something as >> mundane as a package-existence / type-check. >> >> Applications might already, or want to, use #is:. However, any >> overrides of #is: will rob them of the functionality provided by >> Object>>#is:, so a complication is introduced, a choice is forced. >> >> Ok, I might be wrong in a practical-sense about this, since the >> package-existence check would typically be on a PackageInfo object or >> something that probably wouldn't otherwise need #is:. >> >> My only point is that, we should remember to duly consider the >> namespace when consuming a selector as grand as #is: in case it might >> be better-appreciated in the application namespace.. >> >> Regards, >> Chris >> >> > > |
In reply to this post by Andreas.Raab
I don't see how #is: can work in the large.
suppose I need test selectors like isMorph, isBorderedMorph, isMyMorph and isMySpecializedMorph every Morph must have is: aSymbol aSymbol == #Morph ifTrue: [^ true]. ^ false then BorderedMorph must implement is: aSymbol (super is: aSymbol or: [aSymbol == #BorderedMorph]) ifTrue: [^ true]. ^ false now MyMorph (supposedly a BorderedMorph) has is: aSymbol (super is: aSymbol or: [aSymbol == #MyMorph]) ifTrue: [^ true]. ^ false so far so good, although at the moment all this code would be replaced with isMorph ^ false isBorderedMorph ^ false isMyMorph ^ false in Object, and the corresponding isMorph ^ true isBorderedMorph ^ true isMyMorph ^ true at the proper places 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 ? 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 keith1y
On 04.03.2010, at 20:38, keith wrote:
> > Another way of doing this, (last seen in SmalltalkAgents) is to implement askFor: > > anObject askFor: #isMorph. > > We had an ongoing debate on mantis as to whether this should return nil or false by default. (I prefer false, my more purist friends appear to prefer nil) if the selector is not implemented. I would favour this approach because askFor: is useful for other purposes, and in a world where things are more modular and less tightly coupled, it can be useful to have askFor: and askFor: aSelector ifAbsent: > > Keith Wouldn't that be more aptly named perform:ifAbsent: ? - Bert - |
In reply to this post by Stéphane Rollandin
Stéphane,
Am 04.03.2010 um 20:44 schrieb Stéphane Rollandin <[hidden email] t>: > I don't see how #is: can work in the large. doesn't the implementation in Object do what you intend? (??) > I guess I'm missing something. how is this supposed to work ? ... or am I missing something? Best, > Michael |
In reply to this post by Stéphane Rollandin
2010/3/4 Stéphane Rollandin <[hidden email]>:
> I don't see how #is: can work in the large. > > suppose I need test selectors like isMorph, isBorderedMorph, isMyMorph and > isMySpecializedMorph > > every Morph must have > > is: aSymbol > aSymbol == #Morph ifTrue: [^ true]. > ^ false > have such override, since a base method will behave exactly like that for any Morph instance. > then BorderedMorph must implement > > is: aSymbol > (super is: aSymbol > or: [aSymbol == #BorderedMorph]) ifTrue: [^ true]. > ^ false > same as above. You don't need to override it. > now MyMorph (supposedly a BorderedMorph) has > > is: aSymbol > (super is: aSymbol > or: [aSymbol == #MyMorph]) ifTrue: [^ true]. > ^ false > > > so far so good, although at the moment all this code would be replaced with > > isMorph > ^ false > > isBorderedMorph > ^ false > > isMyMorph > ^ false > > in Object, and the corresponding > > > isMorph > ^ true > > isBorderedMorph > ^ true > > isMyMorph > ^ true > > at the proper places > > > 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 ? > A subclass inherits all aspects of parent class. Think how many things you will need to override, if you would want to subclass from a Number but don't behave like number. Obviously, in your example you showing how to not abuse inheritance. And its nothing to do with #is: method :) > 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 ? > I think you should read mail archives. First it was discussed about year ago (if i remember correctly). Then Juan added it into Cius, cleaning a lot of isXXX method. I think, we can ask Juan, how he feels about it, because he's the only one who employed this idea so far. > > Stef > -- Best regards, Igor Stasenko AKA sig. |
On 4 March 2010 22:08, Igor Stasenko <[hidden email]> wrote:
> 2010/3/4 Stéphane Rollandin <[hidden email]>: >> I don't see how #is: can work in the large. >> >> suppose I need test selectors like isMorph, isBorderedMorph, isMyMorph and >> isMySpecializedMorph >> >> every Morph must have >> >> is: aSymbol >> aSymbol == #Morph ifTrue: [^ true]. >> ^ false >> > it much not. If you seen a proposed implementation, you don't need to > have such override, since > a base method will behave exactly like that for any Morph instance. > >> then BorderedMorph must implement >> >> is: aSymbol >> (super is: aSymbol >> or: [aSymbol == #BorderedMorph]) ifTrue: [^ true]. >> ^ false >> > same as above. You don't need to override it. > >> now MyMorph (supposedly a BorderedMorph) has >> >> is: aSymbol >> (super is: aSymbol >> or: [aSymbol == #MyMorph]) ifTrue: [^ true]. >> ^ false >> >> >> so far so good, although at the moment all this code would be replaced with >> >> isMorph >> ^ false >> >> isBorderedMorph >> ^ false >> >> isMyMorph >> ^ false >> >> in Object, and the corresponding >> >> >> isMorph >> ^ true >> >> isBorderedMorph >> ^ true >> >> isMyMorph >> ^ true >> >> at the proper places >> >> >> 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 ? >> > > A subclass inherits all aspects of parent class. > Think how many things you will need to override, if you would want to > subclass from a Number but don't behave like number. > Obviously, in your example you showing how to not abuse inheritance. or hot to abuse it.. whatever. I meant: in your example you having a problems not because of #is: method, but because of abuse of inheritance. > And its nothing to do with #is: method :) > >> 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 ? >> > I think you should read mail archives. > First it was discussed about year ago (if i remember correctly). > Then Juan added it into Cius, cleaning a lot of isXXX method. > I think, we can ask Juan, how he feels about it, because he's the only > one who employed this idea so far. > >> >> Stef >> > > > -- > Best regards, > Igor Stasenko AKA sig. > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Igor Stasenko
> A subclass inherits all aspects of parent class.
> Think how many things you will need to override, if you would want to > subclass from a Number but don't behave like number. If #is: implementation has to reflect a class hierarchy, then I don't see how it can be any better than #isKindOf: and #isMemberOf: > Obviously, in your example you showing how to not abuse inheritance. My example is based on real, actual code. I use quite a feww isXXX methods to ask objects about a property or a protocol they may or not have. It works fine and allows me to control fine discriminations along the inheritance. That's not abusing, that's designing. > And its nothing to do with #is: method :) Yes, because #isXXX messages are quite special methods: they mostly return mere ^true or ^false. So we are talking in this specific case about replacing a simple modular, orthogonal set of clear implementations with something much more complex and messy. > >> 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 ? >> > I think you should read mail archives. I did read the #is: proposal, at the time. No message that I remember addressed the kind of problem I expose above and that I had already in mind (although I did not participate in the discussion). Now I would appreciate a simple answer about what's wrong in my example; if there is confusion at this level, the #is: idea is certainly not as straightforward as it may seem. > Then Juan added it into Cius, cleaning a lot of isXXX method. > I think, we can ask Juan, how he feels about it, because he's the only > one who employed this idea so far. So it may be only a nice idea untested in a real situation. I am very dubious about its actual value; for one thing, it certainly cannot replace the isXXX I use in my own code. regards, Stef |
In reply to this post by Andreas.Raab
Andreas Raab wrote:
> For discussion, this is what I'm suggesting: > > Object>>is: aSymbol > > "A generic membership test. Should be used to avoid the > proliferation of isXXX > methods where appropriate. Use it like here: > > FooBar>>is: aSymbol > ^aSymbol == #Foo or:[aSymbol == #Bar or:[super is: aSymbol]] > > This implementation can also be used with class names to replace > the usage > of aMorph isKindOf: SketchEditorMorph with, e.g., aMorph is: > #SketchEditorMorph > to avoid unnecessary dependencies on classes" > > "Check to see if aSymbol is a class name in the receiver's > environment" > self class environment > at: aSymbol > ifPresent:[:aClass| ^self isKindOf: aClass]. > > ^false I believe #isKindOf: is really bad. Reasons for this are given in http://userweb.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf . This was also discussed here, you can google for the name of the pdf in the archives. In the Cuis implementation of Object>>#is: there is no call to #isKindOf:. The idea is to ask for a protocol, not for inheritance. Cheers, Juan Vuletich |
In reply to this post by Igor Stasenko
Igor Stasenko wrote:
> ... > Then Juan added it into Cius, cleaning a lot of isXXX method. > I think, we can ask Juan, how he feels about it, because he's the only > one who employed this idea so far. I love it. It helps remove a lot of methods in base classes like Object and Morph that don't really belong there. Please note that in Cuis, #is: does not call #isKindOf:. All implementors are explicit. This also means that you can see the protocols an object conforms by reading the inheritance of the #is: method. Cheers, Juan Vuletich |
In reply to this post by Stéphane Rollandin
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. > Yes, because #isXXX messages are quite special methods: they mostly return > mere ^true or ^false. So we are talking in this specific case about > replacing a simple modular, orthogonal set of clear implementations with > something much more complex and messy. I really fail to see how #is: is complex and messy. Really. > Now I would appreciate a simple answer about what's wrong in my example; if > there is confusion at this level, the #is: idea is certainly not as > straightforward as it may seem. All right, I will take another look at it. I must have missed something. :-) Best, Michael |
In reply to this post by Stéphane Rollandin
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 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 Juan Vuletich-4
so how do you handle the kind of problem I submitted ?
Stef |
In reply to this post by Stéphane Rollandin
Stéphane Rollandin wrote:
>> ... > If #is: implementation has to reflect a class hierarchy, then I don't > see how it can be any better than #isKindOf: and #isMemberOf: In my opinion, it does not have to reflect a class hierarchy at all, but conformance to some protocol. Take a look at http://userweb.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf . Cheers, Juan Vuletich |
In reply to this post by Stéphane Rollandin
Hi again,
2010/3/4 Stéphane Rollandin <[hidden email]>: > so how do you handle the kind of problem I submitted ? 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. Best, Michael |
In reply to this post by Stéphane Rollandin
Stéphane Rollandin wrote:
> so how do you handle the kind of problem I submitted ? > > Stef > Had already answered to your original message, just a couple of minutes before this. Please check it. Cheers, Juan Vuletich |
In reply to this post by Michael Haupt-3
> 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: 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. 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. regards, Stef |
In reply to this post by Stéphane Rollandin
2010/3/4 Stéphane Rollandin <[hidden email]>:
>> A subclass inherits all aspects of parent class. >> Think how many things you will need to override, if you would want to >> subclass from a Number but don't behave like number. > > If #is: implementation has to reflect a class hierarchy, then I don't see > how it can be any better than #isKindOf: and #isMemberOf: > >> Obviously, in your example you showing how to not abuse inheritance. > > My example is based on real, actual code. I use quite a feww isXXX methods > to ask objects about a property or a protocol they may or not have. It works > fine and allows me to control fine discriminations along the inheritance. Then, please , give me a concrete example, where you will have 3 classes, answering to isXXX message differently: base (false) -> parent(true) -> subclass(false). > That's not abusing, that's designing. > No it is abuse. By taking your example as a guide, then what stops me from creating Morph subclass, which answers false to isMorph message. Do you still see nothing wrong with it? >> And its nothing to do with #is: method :) > > Yes, because #isXXX messages are quite special methods: they mostly return > mere ^true or ^false. So we are talking in this specific case about > replacing a simple modular, orthogonal set of clear implementations with > something much more complex and messy. > hmm.. i don't see anything messy here. It removes a bloat of #isXXXX methods in many places. Usually, when you introducing a new aspect in your class, you just override the #is: method with following: is: aSymbol ^ aSymbol == #myAspect ifFalse: [ super is: aSymbol ]. While if you use isXXX method, obviously you will need to add it to base class (most of the times - Object) and then override it in your class. >> >>> 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 ? >>> >> I think you should read mail archives. > >> First it was discussed about year ago (if i remember correctly). > > I did read the #is: proposal, at the time. No message that I remember > addressed the kind of problem I expose above and that I had already in mind > (although I did not participate in the discussion). > false to isMorph message. > Now I would appreciate a simple answer about what's wrong in my example; if > there is confusion at this level, the #is: idea is certainly not as > straightforward as it may seem. > >> Then Juan added it into Cius, cleaning a lot of isXXX method. >> I think, we can ask Juan, how he feels about it, because he's the only >> one who employed this idea so far. > > So it may be only a nice idea untested in a real situation. I am very > dubious about its actual value; for one thing, it certainly cannot replace > the isXXX I use in my own code. > variables in your class with variable class, having 100 elements. > regards, > > Stef > -- Best regards, Igor Stasenko AKA sig. |
Free forum by Nabble | Edit this page |