I would like a suggestion on instantiating unknown classes at runtime.
I need to intantiate a class whose name is in a symbol variable. For example normally if I can have a class Date I would send it a new message. myApp := Date perform: #newDay:year: with: 12 with: 2000 However I want to do the same thing based on a class name that is a variable. So I tried the following which works: myAppClass := #Date. mySelector:= #newDay:year:. myAppObject := (Smalltalk at: myAppClass ) perform: mySelector with: 5 with: 2000. Any other more elegant ways? Costas |
> So I tried the following which works:
> > myAppClass := #Date. > mySelector:= #newDay:year:. > myAppObject := (Smalltalk at: myAppClass ) > perform: mySelector with: 5 with: 2000. > > Any other more elegant ways? Apart from not relying on the global Smalltalk holding all the classes, I don't see what could be more elegant. So, I'd just suggest using myAppClass asClass instead of Smalltalk at:. Regards, Peter van Rooijen |
In reply to this post by Costas Menico-2
Costas,
> I need to intantiate a class whose name is in a symbol variable. > For example normally if I can have a class Date I would send it a new > message. > > myApp := Date perform: #newDay:year: with: 12 with: 2000 > > However I want to do the same thing based on a class name that is a > variable. So I tried the following which works: > > myAppClass := #Date. > mySelector:= #newDay:year:. > myAppObject := (Smalltalk at: myAppClass ) > perform: mySelector with: 5 with: 2000. > > Any other more elegant ways? I'm not sure whether your need is to have the method selector in a variable or not. If not, then you can also do: (Smalltalk at: myAppClass) newDay:5 year: 2000 Best regards, Andy Bower Dolphin Support http://www.object-arts.com --- Visit the Dolphin Smalltalk Wiki Web http://www.object-arts.com/wiki/html/Dolphin/FrontPage.htm --- |
In reply to this post by Peter van Rooijen
Peter,
> Apart from not relying on the global Smalltalk holding all the classes, I > don't see what could be more elegant. > > So, I'd just suggest using myAppClass asClass instead of Smalltalk at:. Dolphin, doesn't have #asClass (must be some other popular Smalltalk you are thinking of). In general, we frown upon the us of #asXXXX selectors and tend to follow the recommendations in Beck's Smalltalk Best Practise Patterns.(which has mysteriously disappeared from the bookshelf so I can't quote you the page numbers at the moment). There was a discussion about this in the old newsgroup some time ago so it'll probably be available in the archives. What we usually do to avoid hard coding a reference to the Smalltalk global (and to prepare the road for namespaces in future) is to use #environment to look it up. i.e. (self environment at: myAppClass) newDay:5 year: 2000 You'll see this is used quite a few times in the base image. Best regards, Andy Bower Dolphin Support http://www.object-arts.com --- Visit the Dolphin Smalltalk Wiki Web http://www.object-arts.com/wiki/html/Dolphin/FrontPage.htm --- |
In reply to this post by Andy Bower
Costas,
> > I need to intantiate a class whose name is in a symbol variable. > > For example normally if I can have a class Date I would send it a new > > message. > > > > myApp := Date perform: #newDay:year: with: 12 with: 2000 > > > > However I want to do the same thing based on a class name that is a > > variable. So I tried the following which works: > > > > myAppClass := #Date. > > mySelector:= #newDay:year:. > > myAppObject := (Smalltalk at: myAppClass ) > > perform: mySelector with: 5 with: 2000. > > > > Any other more elegant ways? > > I'm not sure whether your need is to have the method selector in a > or not. If not, then you can also do: > > (Smalltalk at: myAppClass) newDay:5 year: 2000 > Alternatively, create a method, say #myAppClass, which returns the real class name. MyApp>>myAppClass ^Date MyApp>>mySelector ^#newDay:year: then the method to create the date would look like: (self myAppClass) perform: (self mySelector) withAll: #( 5 2000 ) Now you can have different subclasses, all returning a different class and a different selector. The generic code in the superclass stays the same. HTH Ted |
In reply to this post by Peter van Rooijen
"Peter van Rooijen" <[hidden email]> wrote:
>> So I tried the following which works: >> >> myAppClass := #Date. >> mySelector:= #newDay:year:. >> myAppObject := (Smalltalk at: myAppClass ) >> perform: mySelector with: 5 with: 2000. >> >> Any other more elegant ways? > >Apart from not relying on the global Smalltalk holding all the classes, I >don't see what could be more elegant. > >So, I'd just suggest using myAppClass asClass instead of Smalltalk at:. > First thing I tried... but as you can see from Andy's response I have to consult my patterns too <g>. Costas |
In reply to this post by Andy Bower
"Andy Bower" <[hidden email]> wrote:
> >What we usually do to avoid hard coding a reference to the Smalltalk global >(and to prepare the road for namespaces in future) is to use #environment to >look it up. i.e. what version of Dolphin should we expect namespaces in? Costas > |
In reply to this post by Costas Menico-2
"Costas Menico" <[hidden email]> wrote in message
news:[hidden email]... > "Peter van Rooijen" <[hidden email]> wrote: > > >> So I tried the following which works: > >> > >> myAppClass := #Date. > >> mySelector:= #newDay:year:. > >> myAppObject := (Smalltalk at: myAppClass ) > >> perform: mySelector with: 5 with: 2000. > >> > >> Any other more elegant ways? > > > >Apart from not relying on the global Smalltalk holding all the classes, I > >don't see what could be more elegant. > > > >So, I'd just suggest using myAppClass asClass instead of Smalltalk at:. > > > > First thing I tried... but as you can see from Andy's response I have > to consult my patterns too <g>. Ho! Not so fast! 1. Because Kent says so, doesn't make it right. 2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want protocol explosion, which he sees as a danger because there is no theoretical limit to the number of conversion methods you could add. This in *not* a case where you are in danger of a conversion protocol explosion. 3. In fact, Kent explicitly mentions (p. 29) that he would be happy to use a conversion method where there is only one reasonable way to do the conversion, as is the case with the conversion from Symbol to Class. 4. Don't take my word for it, ask Kent what he thinks about #asClass. 5. #asClass isn't really a standard conversion method. If you feel it could be unrevealing of its intention (I think, slim chance of that), use Class withName: aString. It's a little longer, but it also communicates just a little more. Finally, I wasn't suggesting the method is in the Dolphin base system. I was suggesting Costas use it, for elegance, as per his request. Regards, Peter |
In reply to this post by Andy Bower
"Andy Bower" <[hidden email]> wrote in message
news:91n9pd$4hltt$[hidden email]... > Peter, > > > Apart from not relying on the global Smalltalk holding all the classes, I > > don't see what could be more elegant. > > > > So, I'd just suggest using myAppClass asClass instead of Smalltalk at:. > > Dolphin, doesn't have #asClass (must be some other popular Smalltalk you are > thinking of). > > In general, we frown upon the us of #asXXXX selectors and tend to follow the > recommendations in Beck's Smalltalk Best Practise Patterns.(which has > mysteriously disappeared from the bookshelf so I can't quote you the page > numbers at the moment). That's okay. I looked it up and what you say is his recommendation, actually isn't. See my post to Costas. > There was a discussion about this in the old > newsgroup some time ago so it'll probably be available in the archives. > What we usually do to avoid hard coding a reference to the Smalltalk global > (and to prepare the road for namespaces in future) is to use #environment to > look it up. i.e. > > (self environment at: myAppClass) newDay:5 year: 2000 > > You'll see this is used quite a few times in the base image. Might I respectfully suggest you refactor that code duplication ;-). Best regards, Peter > Best regards, > > Andy Bower > Dolphin Support > http://www.object-arts.com > > --- > Visit the Dolphin Smalltalk Wiki Web > http://www.object-arts.com/wiki/html/Dolphin/FrontPage.htm > --- > > |
In reply to this post by Peter van Rooijen
Peter,
>1. Because Kent says so, doesn't make it right. >2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want >protocol explosion, which he sees as a danger because there is no >theoretical limit to the number of conversion methods you could add. This in >*not* a case where you are in danger of a conversion protocol explosion. >3. In fact, Kent explicitly mentions (p. 29) that he would be happy to use a >conversion method where there is only one reasonable way to do the >conversion, as is the case with the conversion from Symbol to Class. I agree that just because Kent said it it does not make it right. Patterns are advisory as are many things in Smalltalk. There are many exceptions to the rules. >4. Don't take my word for it, ask Kent what he thinks about #asClass. Hmmm, does he still work with Smalltalk? >5. #asClass isn't really a standard conversion method. If you feel it could >be unrevealing of its intention (I think, slim chance of that), use Class >withName: aString. It's a little longer, but it also communicates just a >little more. > >Finally, I wasn't suggesting the method is in the Dolphin base system. I was >suggesting Costas use it, for elegance, as per his request. No question #asClass or Class withname: asString would be more meaningful. However I for my own reasons am trying to refrain from adding code to the base image of Dolphin. I think for this I will just use what is available and just write a comment next to it. Costas |
Hi guys,
If I might make a suggestion that would be a more general mapping pattern (that also happens to be compatible with features in SmallScript :-). You might want to try implementing: #as: ... "in <Object>" This has the advantage that there is only ONE generalized selector #as:. Then a variety of techniques like double dispatching or multi-method checking can be done to handle the conversion. As in: =================== <?method [ as: aMapper ^aMapper asMapped: self ]?> <?method class=Class [ asMapped: descriptor ^Smalltalk at: descriptor "or whatever is appropriate" ]?> <?method class=Boolean [ asMapped: descriptor ^descriptor !== false and: [descriptor !== nil and: [descriptor != 0]] ]?> <?method class=Interface "in SmallScript" [ asMapped: descriptor ... ]?> =================== Then one can write code like: a) anObject as: #String. b) anObject as: Boolean. *) anObject as: <some-class or some-interface> -- -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." "Costas Menico" <[hidden email]> wrote in message news:[hidden email]... > Peter, > > >1. Because Kent says so, doesn't make it right. > >2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want > >protocol explosion, which he sees as a danger because there is no > >theoretical limit to the number of conversion methods you could add. This in > >*not* a case where you are in danger of a conversion protocol explosion. > >3. In fact, Kent explicitly mentions (p. 29) that he would be happy to use a > >conversion method where there is only one reasonable way to do the > >conversion, as is the case with the conversion from Symbol to Class. > > I agree that just because Kent said it it does not make it right. > Patterns are advisory as are many things in Smalltalk. There are many > exceptions to the rules. > > >4. Don't take my word for it, ask Kent what he thinks about #asClass. > > Hmmm, does he still work with Smalltalk? > > >5. #asClass isn't really a standard conversion method. If you feel it > >be unrevealing of its intention (I think, slim chance of that), use Class > >withName: aString. It's a little longer, but it also communicates just a > >little more. > > > >Finally, I wasn't suggesting the method is in the Dolphin base system. I was > >suggesting Costas use it, for elegance, as per his request. > > No question #asClass or Class withname: asString would be more > meaningful. However I for my own reasons am trying to refrain from > adding code to the base image of Dolphin. > > I think for this I will just use what is available and just write a > comment next to it. > > Costas |
In reply to this post by Costas Menico-2
"David Simmons" <[hidden email]> wrote in message news:...
> Hi guys, > > If I might make a suggestion that would be a more general mapping pattern > (that also happens to be compatible with features in SmallScript :-). > > You might want to try implementing: > > #as: ... "in <Object>" > > This has the advantage that there is only ONE generalized selector #as:. > Then a variety of techniques like double dispatching or multi-method > checking can be done to handle the conversion. > > As in: > =================== > <?method [ > as: aMapper > ^aMapper asMapped: self > ]?> > > <?method class=Class [ > asMapped: descriptor > > ^Smalltalk at: descriptor "or whatever is appropriate" > ]?> > > <?method class=Boolean [ > asMapped: descriptor > ^descriptor !== false > and: [descriptor !== nil > and: [descriptor != 0]] > ]?> > > <?method class=Interface "in SmallScript" [ > asMapped: descriptor > ... > ]?> > =================== > > Then one can write code like: > > a) > anObject as: #String. "WRONG -- I'm a dummy" Uhhh, duh. I went to all the trouble to write the post and then stupidly wrote the wrong answer here... "SHOULD BE" a) #someClassName as: Class. > > b) > anObject as: Boolean. > > *) > anObject as: <some-class or some-interface> > > -- > -- Dave Simmons [www.qks.com / www.smallscript.com] > "Effectively solving a problem begins with how you express it." > > > "Costas Menico" <[hidden email]> wrote in message > news:[hidden email]... > > Peter, > > > > >1. Because Kent says so, doesn't make it right. > > >2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want > > >protocol explosion, which he sees as a danger because there is no > > >theoretical limit to the number of conversion methods you could add. > in > > >*not* a case where you are in danger of a conversion protocol explosion. > > >3. In fact, Kent explicitly mentions (p. 29) that he would be happy to > use a > > >conversion method where there is only one reasonable way to do the > > >conversion, as is the case with the conversion from Symbol to Class. > > > > I agree that just because Kent said it it does not make it right. > > Patterns are advisory as are many things in Smalltalk. There are many > > exceptions to the rules. > > > > >4. Don't take my word for it, ask Kent what he thinks about #asClass. > > > > Hmmm, does he still work with Smalltalk? > > > > >5. #asClass isn't really a standard conversion method. If you feel it > could > > >be unrevealing of its intention (I think, slim chance of that), use > > >withName: aString. It's a little longer, but it also communicates just a > > >little more. > > > > > >Finally, I wasn't suggesting the method is in the Dolphin base system. I > was > > >suggesting Costas use it, for elegance, as per his request. > > > > No question #asClass or Class withname: asString would be more > > meaningful. However I for my own reasons am trying to refrain from > > adding code to the base image of Dolphin. > > > > I think for this I will just use what is available and just write a > > comment next to it. > > > > Costas > > |
Dag nammit. I did it again. I was called to dinner a while ago and I've been
rushing to get this post out. It's stupid I know. I apologize for a third try to get it right... "David Simmons" <[hidden email]> wrote in message news:XGU%5.10938$[hidden email]... > "David Simmons" <[hidden email]> wrote in message news:... > > Hi guys, > > > > If I might make a suggestion that would be a more general mapping pattern > > (that also happens to be compatible with features in SmallScript :-). > > > > You might want to try implementing: > > > > #as: ... "in <Object>" > > > > This has the advantage that there is only ONE generalized selector #as:. > > Then a variety of techniques like double dispatching or multi-method > > checking can be done to handle the conversion. > > > > As in: > > =================== "THIS SHOULD SPECIFY class=Object" > > <?method [ > > as: aMapper > > ^aMapper asMapped: self > > ]?> As in: <?method class=Object [ as: aMapper ^aMapper asMapped: self ]?> > > > > <?method class=Class [ > > asMapped: descriptor > > > > ^Smalltalk at: descriptor "or whatever is appropriate" > > ]?> > > > > <?method class=Boolean [ > > asMapped: descriptor > > ^descriptor !== false > > and: [descriptor !== nil > > and: [descriptor != 0]] > > ]?> > > > > <?method class=Interface "in SmallScript" [ > > asMapped: descriptor > > ... > > ]?> > > =================== > > > > Then one can write code like: > > > > a) > > anObject as: #String. "WRONG -- I'm a dummy" > > Uhhh, duh. I went to all the trouble to write the post and then stupidly > wrote the wrong answer here... > "SHOULD BE" > a) > #someClassName as: Class. > > > > b) > > anObject as: Boolean. > > > > *) > > anObject as: <some-class or some-interface> > > > > -- > > -- Dave Simmons [www.qks.com / www.smallscript.com] > > "Effectively solving a problem begins with how you express it." > > > > > > "Costas Menico" <[hidden email]> wrote in message > > news:[hidden email]... > > > Peter, > > > > > > >1. Because Kent says so, doesn't make it right. > > > >2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't > > > >protocol explosion, which he sees as a danger because there is no > > > >theoretical limit to the number of conversion methods you could add. > This > > in > > > >*not* a case where you are in danger of a conversion protocol > explosion. > > > >3. In fact, Kent explicitly mentions (p. 29) that he would be happy to > > use a > > > >conversion method where there is only one reasonable way to do the > > > >conversion, as is the case with the conversion from Symbol to Class. > > > > > > I agree that just because Kent said it it does not make it right. > > > Patterns are advisory as are many things in Smalltalk. There are many > > > exceptions to the rules. > > > > > > >4. Don't take my word for it, ask Kent what he thinks about #asClass. > > > > > > Hmmm, does he still work with Smalltalk? > > > > > > >5. #asClass isn't really a standard conversion method. If you feel it > > could > > > >be unrevealing of its intention (I think, slim chance of that), use > Class > > > >withName: aString. It's a little longer, but it also communicates > a > > > >little more. > > > > > > > >Finally, I wasn't suggesting the method is in the Dolphin base system. > I > > was > > > >suggesting Costas use it, for elegance, as per his request. > > > > > > No question #asClass or Class withname: asString would be more > > > meaningful. However I for my own reasons am trying to refrain from > > > adding code to the base image of Dolphin. > > > > > > I think for this I will just use what is available and just write a > > > comment next to it. > > > > > > Costas > > > > > > |
"David Simmons" <[hidden email]> wrote:
>Dag nammit. I did it again. I was called to dinner a while ago and I've been >rushing to get this post out. It's stupid I know. I apologize for a third >try to get it right... > I think I will wait until later to study your posts. Make sure there is nothing else you left out <g>... |
In reply to this post by David Simmons
David Simmons wrote:
> > Hi guys, > > If I might make a suggestion that would be a more general mapping pattern > (that also happens to be compatible with features in SmallScript :-). > > You might want to try implementing: > > #as: ... "in <Object>" > > This has the advantage that there is only ONE generalized selector #as:. Thank you, this helped me in something I was doing the other day. I found even that squeak already had Object>>as: aSimilarClass ^ aSimilarClass newFrom: self So I just added: Class class>>newFrom: aSymbolOrString ^ Smalltalk at: aSymbolOrString asSymbol 'Date' as: Class ==>Date Great! Thanks again! Cheers, John |
"John Clonts" <[hidden email]> wrote in message
news:[hidden email]... > David Simmons wrote: > > > > Hi guys, > > > > If I might make a suggestion that would be a more general mapping pattern > > (that also happens to be compatible with features in SmallScript :-). > > > > You might want to try implementing: > > > > #as: ... "in <Object>" > > > > This has the advantage that there is only ONE generalized selector #as:. > [snipped excellent elaboration] > > Thank you, this helped me in something I was doing the other day. > > I found even that squeak already had > Object>>as: aSimilarClass > ^ aSimilarClass newFrom: self > > So I just added: > Class class>>newFrom: aSymbolOrString > ^ Smalltalk at: aSymbolOrString asSymbol Cool. I'm glad it helped despite my rewrites. By the way, did you notice that you still use #asSymbol. ^Smalltalk at: (aSymbolOrString as: Symbol) I'm not suggesting you shouldn't but it is worth noticing... -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." > > > 'Date' as: Class ==>Date > > Great! Thanks again! > > Cheers, > John |
"David Simmons" <[hidden email]> wrote in message
news:A0Z%5.13077$[hidden email]... > "John Clonts" <[hidden email]> wrote in message > news:[hidden email]... > > David Simmons wrote: > > > > > > Hi guys, > > > > > > If I might make a suggestion that would be a more general mapping > pattern > > > (that also happens to be compatible with features in SmallScript :-). > > > > > > You might want to try implementing: > > > > > > #as: ... "in <Object>" > > > > > > This has the advantage that there is only ONE generalized selector > > [snipped excellent elaboration] > > > > Thank you, this helped me in something I was doing the other day. > > > > I found even that squeak already had > > Object>>as: aSimilarClass > > ^ aSimilarClass newFrom: self > > > > So I just added: > > Class class>>newFrom: aSymbolOrString > > ^ Smalltalk at: aSymbolOrString asSymbol > > Cool. I'm glad it helped despite my rewrites. > > By the way, did you notice that you still use #asSymbol. > > ^Smalltalk at: (aSymbolOrString as: Symbol) > > I'm not suggesting you shouldn't but it is worth noticing... > > -- Dave Simmons [www.qks.com / www.smallscript.com] > "Effectively solving a problem begins with how you express it." Ok, so I probably should elaborate on this. And, it turns out to be a good basis for explaining a number of other related benefits and reasons for utilizing this kind of design/architecture. First, let me point out that executing #asSymbol is a single dispatch for the case of <self> being a <Symbol>, vis-a-vis #as:<Symbol> which results in a double dispatch. Without multi-method dispatch one could argue that double dispatching all conversions is more expensive in terms of performance. I.e., "aSymbol asSymbol" is about as efficient as it gets for jitted execution. Whereas "aSymbol as: Symbol" results in a double dispatch and probably a type check in the second method -- so it is quite a bit more expensive. Read on to see how multi-method dispatch restores the performance balance while retaining the ability to generalize with #as:. I.e., you would want both: "General method to obtain a canonically unique Symbol given a String" <?method class='Symbol.class' [ asMapped: <String> descriptor ...String to Symbol parse and intern code... ]?> "This is the method that gets you the same performance as you have with traditional #asSymbol." <?method class=Symbol [ as: <Symbol> ^self ]?> =============== How does this work? Given: x as: Symbol If <x> is a <Symbol>, then the multi-method Symbol::as:(<Symbol>) would be invoked with exactly the same performance benefits as #asSymbol. I.e., no double dispatch. One-arg multi-method dispatch is almost identical performance as non-multi-method dispatch. If, on the other hand, <x> is a <String> then it would be double-dispatched via Object::as:(<any>) to Symbol.class::asMapped:(<String>). Furthermore, as we note later on, the intern code will only be invoked if the <descriptor> is a type of <String> (an instance of <String> or one of its subclasses). Which is the same mechanism that #asSymbol typically uses. Unless, the <Symbol> intern code is actually performed in the Object::asSymbol() method. While that is not how I would write it (because it is both a <Symbol> operation and it clutters <Object>), one could achieve that same mechanism by moving the code from Symbol.class::asMapped:(<String>). AS IN: <?method class='Symbol.class' [ asMapped: <String> descriptor ...String to Symbol parse and intern code... ]?> TO <?method class=Object [ as: <Symbol.class> aMapper ...String to Symbol parse and intern code... ]?> Finally, with multi-method binding we have added type safety. First our <Symbol> intern code will only be invoked with a <descriptor> that is a <String> or one of its subclasses. Second, as a result, we've pushed the contract compliance responsibility off our implementation shoulders and onto the callee's implementation shoulders (where it belongs). In other words, multi-methods have allowed us to have runtime guaranteed behavior/contract safety in our methods. That means contract failure is no longer the responsibility of the provider, it becomes the exclusive responsibility of the consumer/client. In this system we would get a DNR at the callsite for an expression of the form: 123 as: Symbol Whereas, without multi-method contract support the validation and thus failure point would be shifted to somewhere in the internals of the callee. Which: (1) might make it much harder to figure out what the real problem was; (2) mean that as a "provider" we have to have more assertion/type-checks; (3) we might end up with side-effects for actions taken in the internals of the "provider" and therefore require more design work to add transaction semantics that allow reversing of the side-effects. I.e., 123 as: Symbol Would presumably cause some exception inside the bowels of the <Symbol> intern code. If you extrapolate this reasonably simple example to a complex application/framework architecture it could be much more challenging to validate and/or debug problems because the contract is not runtime enforced. Hence, we would want to write/provide a significantly larger set of unit tests just to achieve a corresponding level of contract assertion/enforcement. And that, in a nutshell, is the dynamic runtime equivalent of static (compile time) type safety/correctness behavior. Interfaces (mixin types), parametric polymorphism, and a few other things make the story even more attractive for dynamic type systems. -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." > > > > > > > 'Date' as: Class ==>Date > > > > Great! Thanks again! > > > > Cheers, > > John > > |
"David Simmons" <[hidden email]> wrote in message
news:qDZ%5.13164$[hidden email]... > "David Simmons" <[hidden email]> wrote in message > news:A0Z%5.13077$[hidden email]... > > "John Clonts" <[hidden email]> wrote in message > > news:[hidden email]... > > > David Simmons wrote: > > > > > > > > Hi guys, > > > > > > > > If I might make a suggestion that would be a more general mapping > > pattern > > > > (that also happens to be compatible with features in SmallScript > > > > > > > > You might want to try implementing: > > > > > > > > #as: ... "in <Object>" > > > > > > > > This has the advantage that there is only ONE generalized selector > #as:. > > > [snipped excellent elaboration] > > > > > > Thank you, this helped me in something I was doing the other day. > > > > > > I found even that squeak already had > > > Object>>as: aSimilarClass > > > ^ aSimilarClass newFrom: self > > > > > > So I just added: > > > Class class>>newFrom: aSymbolOrString > > > ^ Smalltalk at: aSymbolOrString asSymbol > > > > Cool. I'm glad it helped despite my rewrites. > > > > By the way, did you notice that you still use #asSymbol. > > > > ^Smalltalk at: (aSymbolOrString as: Symbol) > > > > I'm not suggesting you shouldn't but it is worth noticing... > > > > -- Dave Simmons [www.qks.com / www.smallscript.com] > > "Effectively solving a problem begins with how you express it." > > Ok, so I probably should elaborate on this. And, it turns out to be a good > basis for explaining a number of other related benefits and reasons for > utilizing this kind of design/architecture. > > First, let me point out that executing #asSymbol is a single dispatch for > the case of <self> being a <Symbol>, vis-a-vis #as:<Symbol> which results > a double dispatch. > > Without multi-method dispatch one could argue that double dispatching all > conversions is more expensive in terms of performance. I.e., "aSymbol > asSymbol" is about as efficient as it gets for jitted execution. Whereas > "aSymbol as: Symbol" results in a double dispatch and probably a type check > in the second method -- so it is quite a bit more expensive. Read on to see > how multi-method dispatch restores the performance balance while retaining > the ability to generalize with #as:. > > I.e., you would want both: > > "General method to obtain a canonically unique Symbol given a String" > <?method class='Symbol.class' [ > asMapped: <String> descriptor > ...String to Symbol parse and intern code... > ]?> > > "This is the method that gets you the same performance > as you have with traditional #asSymbol." > <?method class=Symbol [ > as: <Symbol> > ^self > ]?> ------- BUG FIX: Today is clearly not a good day for me :( ------- <?method class=Symbol [ as: <Symbol.class> "<-- Symbol.class not Symbol" ^self ]?> I really should just grab real code from the system rather than writing this stuff off the top of my clearly overtaxed head. > =============== > > How does this work? > > Given: > x as: Symbol > > If <x> is a <Symbol>, then the multi-method Symbol::as:(<Symbol>) would be > invoked with exactly the same performance benefits as #asSymbol. I.e., no > double dispatch. One-arg multi-method dispatch is almost identical > performance as non-multi-method dispatch. > > If, on the other hand, <x> is a <String> then it would be > via Object::as:(<any>) to Symbol.class::asMapped:(<String>). Furthermore, as > we note later on, the intern code will only be invoked if the <descriptor> > is a type of <String> (an instance of <String> or one of its subclasses). > > Which is the same mechanism that #asSymbol typically uses. Unless, the > <Symbol> intern code is actually performed in the Object::asSymbol() method. > While that is not how I would write it (because it is both a <Symbol> > operation and it clutters <Object>), one could achieve that same mechanism > by moving the code from Symbol.class::asMapped:(<String>). > > AS IN: > > <?method class='Symbol.class' [ > asMapped: <String> descriptor > ...String to Symbol parse and intern code... > ]?> > > TO > > <?method class=Object [ > as: <Symbol.class> aMapper > ...String to Symbol parse and intern code... > ]?> > > Finally, with multi-method binding we have added type safety. First our > <Symbol> intern code will only be invoked with a <descriptor> that is a > <String> or one of its subclasses. Second, as a result, we've pushed the > contract compliance responsibility off our implementation shoulders and > the callee's implementation shoulders (where it belongs). > > In other words, multi-methods have allowed us to have runtime guaranteed > behavior/contract safety in our methods. That means contract failure is no > longer the responsibility of the provider, it becomes the exclusive > responsibility of the consumer/client. > > In this system we would get a DNR at the callsite for an expression of the > form: > > 123 as: Symbol > > Whereas, without multi-method contract support the validation and thus > failure point would be shifted to somewhere in the internals of the > Which: (1) might make it much harder to figure out what the real problem > was; (2) mean that as a "provider" we have to have more > assertion/type-checks; (3) we might end up with side-effects for actions > taken in the internals of the "provider" and therefore require more design > work to add transaction semantics that allow reversing of the side-effects. > > I.e., > > 123 as: Symbol > > Would presumably cause some exception inside the bowels of the <Symbol> > intern code. > > If you extrapolate this reasonably simple example to a complex > application/framework architecture it could be much more challenging to > validate and/or debug problems because the contract is not runtime > Hence, we would want to write/provide a significantly larger set of unit > tests just to achieve a corresponding level of contract > assertion/enforcement. > > And that, in a nutshell, is the dynamic runtime equivalent of static > (compile time) type safety/correctness behavior. Interfaces (mixin types), > parametric polymorphism, and a few other things make the story even more > attractive for dynamic type systems. > > -- Dave Simmons [www.qks.com / www.smallscript.com] > "Effectively solving a problem begins with how you express it." > > > > > > > > > > > > 'Date' as: Class ==>Date > > > > > > Great! Thanks again! > > > > > > Cheers, > > > John > > > > > > |
In reply to this post by Peter van Rooijen
Peter
You wrote in message news:91odoc$q0s$[hidden email]... > > "Costas Menico" <[hidden email]> wrote in message > >... > > First thing I tried... but as you can see from Andy's response I have > > to consult my patterns too <g>. > > Ho! Not so fast! Apologies for belatedly stepping into the middle of this conversation, but as I do posess a copy of the aforementioned tome I am going to support my colleague. > > 1. Because Kent says so, doesn't make it right. Actually I don't think Andy was citing Kent because he is a blind follower of the Beck faith. He (Kent) does happen to be a person who has a lucid way of setting down opinions with which we tend to feel an affinity based on our own experience. A citation is an economical way to transmit a well argued point of view without regurgitating it. When the citee is also a well respected individual then that opinion should rightly carry more weight. Your contradiction may also not be right, and that of course the reader must judge. Of course when your own book is published Peter, we'll doubtless have another lucid reference to cite. > 2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want > protocol explosion, which he sees as a danger because there is no > theoretical limit to the number of conversion methods you could add. Well, your interpretation may be that Kent doesn't say so. Whether he does or does not, he does say rather more than that over those 2 pages. He mentions another problem - that of creating a tie between the classes. Classes and Symbols are fundamental base classes, so this is probably not an issue in practical terms. It is though creating a coupling that need not exist. >...This in > *not* a case where you are in danger of a conversion protocol explosion. I don't think one should attribute the explosion to any one case. Each converter method contributes a little, so it is blind application of the pattern which causes the explosion. > 3. In fact, Kent explicitly mentions (p. 29) that he would be happy to use a > conversion method where there is only one reasonable way to do the > conversion, as is the case with the conversion from Symbol to Class. He does say that, but you have omitted his first precondition for implementing a converter method, which is that the "source and destination of conversion share the same protocol." Clearly not the case here. Personally I don't think it is even correct to say that there is only one way to perform that conversion. That is probably true in Dolphin as it stands today (although the presence of demand loaded binary classes that don't appear in the system dictionary is a possible counter example), but in a future system with namespaces there might be a choice of binding algorithms to use to locate the class. How should the converter method locate the class (i.e. in which namespace). Does it have sufficient context to do that? The natural lookup path would seem to be to first try the namespace of the calling context, information which is not available without using reflective means to access the sender on the stack. Lastly there is a third precondition that I think should apply but which Kent does not mention - the conversion should be possible without error for the majority of cases. Perhaps this doesn't merit status as a pre-condition, but I hope you will agree that a conversion method which fails for 92% of existing instances (only 8% of the Symbols in my D4 image are class names) has a fishy smell about it. > 4. Don't take my word for it, ask Kent what he thinks about #asClass. I'll have leave that to you - we haven't been introduced :-) > 5. #asClass isn't really a standard conversion method. If you feel it could > be unrevealing of its intention (I think, slim chance of that), use Class > withName: aString. It's a little longer, but it also communicates just a > little more. I'd agree with that. If a method in Symbol is needed (certainly it is useful, however dubious) then it should have a name that indicates that it is a class lookup since I wouldn't consider this to be a "conversion" at all. Though it pains me to say it, what is really needed here is some more syntax. There should be a way to specify a late-bound reference to a class in a declarative manner, rather than using some arbitrary expression. The ability to identify and track such binding references is important for both automated tools (image stripping springs to mind) and programmers alike. Regards Blair |
Hi Blair,
"Blair McGlashan" <[hidden email]> wrote in message news:92daqb$6iv88$[hidden email]... > Peter > > You wrote in message news:91odoc$q0s$[hidden email]... > > > > "Costas Menico" <[hidden email]> wrote in message > > >... > > > First thing I tried... but as you can see from Andy's response I have > > > to consult my patterns too <g>. > > > > Ho! Not so fast! > > Apologies for belatedly stepping into the middle of this conversation, You are very welcome! > but > as I do posess a copy of the aforementioned tome I am going to support my > colleague. Good. > > > > 1. Because Kent says so, doesn't make it right. > > Actually I don't think Andy was citing Kent because he is a blind follower > of the Beck faith. And I didn't say or think that. It was mostly Costas' remark that I was reacting to, who suggested that it was necessary for us to consult our patterns. > He (Kent) does happen to be a person who has a lucid way > of setting down opinions with which we tend to feel an affinity based on our > own experience. I completely agree with that. > A citation is an economical way to transmit a well argued > point of view without regurgitating it. When the citee is also a well > respected individual then that opinion should rightly carry more weight. Absolutely. > Your contradiction may also not be right, and that of course the reader must > judge. Actually, I agree with Kent. The main intent of my material remarks was to offer a different interpretation of what Kent wrote, than Andy's. > Of course when your own book is published Peter, we'll doubtless have > another lucid reference to cite. Well, thanks! I can't tell you when it will be out, but It's now almost certain it will be an e-book (that means non-paper, folks), and the title is expected to be 'How To Code Smalltalk' and it will likely have the subtitle 'IBM Smalltalk / VisualAge edition'. You could probably pay me to do the Dolphin edition first, though ;-). > > 2. Kent doesn't say so. What he says (p. 28-29) is that he doesn't want > > protocol explosion, which he sees as a danger because there is no > > theoretical limit to the number of conversion methods you could add. > > Well, your interpretation may be that Kent doesn't say so. And it may be wrong, certainly. Especially as I have been exploiting some ambiguity in what Kent wrote ;-). > Whether he does > or does not, he does say rather more than that over those 2 pages. He > mentions another problem - that of creating a tie between the classes. > Classes and Symbols are fundamental base classes, so this is probably not an > issue in practical terms. I agree, and I put it to you, that that in itself probably makes all the other arguments moot, because it makes Symbol>asClass acceptable (or am I misunderstanding you?). > It is though creating a coupling that need not > exist. Why? And where is the coupling? I see coupling in the implementation of Symbol>>asClass ^Smalltalk classAt: self "will return nil if no class of the name is found" This is only one method in Symbol with one reference to a global, and one foreign selector! There is no coupling in the reverse direction. How much lower coupling can you get without staying entirely inside your own module? Besides, the coupling is the whole idea of the programmer calling the method, isn't it? > >...This in > > *not* a case where you are in danger of a conversion protocol explosion. > > I don't think one should attribute the explosion to any one case. Each > converter method contributes a little, so it is blind application of the > pattern which causes the explosion. I read Kent's story about the group who wrote asXXX for every class in the domain code as illustration of what he means by 'protocol explosion'; that situation lead to every new class starting out with dozens of methods just for converting, without it adding anything to the system otherwise. I can see that you don't want that. And I contend that Symbol>>asClass is a completely different case. > > 3. In fact, Kent explicitly mentions (p. 29) that he would be happy to use > a > > conversion method where there is only one reasonable way to do the > > conversion, as is the case with the conversion from Symbol to Class. > > He does say that, but you have omitted his first precondition for > implementing a converter method, which is that the "source and destination > of conversion share the same protocol." > Clearly not the case here. That only holds if the conditions are cumulative. If they are alternative (which is not an ureasonable position to take, I would say), it doesn't. Certainly, Kent's own examples don't conform to the criteria as you (seem to :-)) interpret them: Collection>>asSet - Set supports Collection's protocol, but not the other way around (condition 1 only half satisfied) - Is there only one reasonable implementation? ^(Set new: self size) addAll: self; yourself seems reasonable. Is it the only one? I'd want to redefine it as ^self in Set. Does that count as more than one way? Number>>asFloat - Condition 1 only half satisfied, as above - Integer>>asFloat is a good candidate for a primitive, some others come to mind for different Number subclasses. Condition 2 most probably not satisfied. > Personally I don't think it is even correct to say that there is only one > way to perform that conversion. I'm agreeing. > That is probably true in Dolphin as it > stands today (although the presence of demand loaded binary classes that > don't appear in the system dictionary is a possible counter example), but in > a future system with namespaces there might be a choice of binding > algorithms to use to locate the class. How should the converter method > locate the class (i.e. in which namespace). Does it have sufficient context > to do that? The natural lookup path would seem to be to first try the > namespace of the calling context, information which is not available without > using reflective means to access the sender on the stack. Interesting issue, still. Binding things to names is what programming is all about. > Lastly there is a third precondition that I think should apply but which > Kent does not mention - the conversion should be possible without error for > the majority of cases. Perhaps this doesn't merit status as a pre-condition, > but I hope you will agree that a conversion method which fails for 92% of > existing instances (only 8% of the Symbols in my D4 image are class names) > has a fishy smell about it. I'm pretty sure nowhere mear that percentage of calls to Symbol>>asClass fails in the image of anyone using it :-). And I think you'd most probably agree. The metric you're proposing is not a very relevant criterium. Or have you ever thought, hey let's write Symbol>>asClass, then run Symbol allInstances do: #asClass and see if it fails? I'll bet you haven't! > > 4. Don't take my word for it, ask Kent what he thinks about #asClass. > > I'll have leave that to you - we haven't been introduced :-) Kent's (yes/no) answer is not important to me. I decide for myself, based on thought, knowing Kent's excellent writings. Perhaps to someone else, it matters. > > 5. #asClass isn't really a standard conversion method. If you feel it > could > > be unrevealing of its intention (I think, slim chance of that), use Class > > withName: aString. It's a little longer, but it also communicates just a > > little more. > > I'd agree with that. If a method in Symbol is needed (certainly it is > useful, however dubious) then it should have a name that indicates that it > is a class lookup since I wouldn't consider this to be a "conversion" at > all. Well, I believe that there is little concern that #AbcDatabaseConnection asClass will be misunderstood. So, what's wrong with it? That seems to be the central question, after all. > Though it pains me to say it, what is really needed here is some more > syntax. There should be a way to specify a late-bound reference to a class > in a declarative manner, rather than using some arbitrary expression. The > ability to identify and track such binding references is important for both > automated tools (image stripping springs to mind) and programmers alike. I think I agree with that general idea. But when is the right time for binding, then? All I can think of, if not compile-time, is the latest possible time. With the variations 'bound once', and 'bound at each activation'. Interesting, indeed. Think you'll do it? I've long yearned for 'once blocks' anyway, BTW. Best regards, Peter |
Free forum by Nabble | Edit this page |