Given Smalltalk's almost infinite reflection capabilities, I assumed it
must be trivial to pass to a method a selector in its calling parameters, but I cannot figure out how to do it. Suppose I have a method like" fooClass>>doSomething: withThisMethod anObject withThisMethod withThisMethod is passed to the the method doSomething as a string and must be converted to a selector in the method's body. How can I do that? Or I may be trying to solve my problem the wrong way. Perhaps the best way to approach this issue is to pass a block of code instead? Thanks for the help. Stefano __________________________________________________ Stefano Franchi Department of Philosophy Ph: (64) 9 373-7599 x83940 University Of Auckland Fax: (64) 9 373-8768 Private Bag 92019 [hidden email] Auckland New Zealand |
On 17/03/07, Stefano Franchi <[hidden email]> wrote:
> Or I may be trying to solve my problem the wrong way. Perhaps the best > way to approach this issue is to pass a block of code instead? Yes. Exactly. You *can* pass a selector in the form of a Symbol, e.g. #at:put: and then you can send a message to an object with that selector using >>perform and variants. But avoid doing that it you possibly can. >>perform will make your code harder to refactor and harder to debug. All the best, Bruce -- Make the most of your skills - with OpenSkills http://www.openskills.org/ |
In reply to this post by stefano-franchi
Stefano,
The solution is called perform: aSymbol, perform: aSymbol with: anObject, and perform: aSymbol withArguments: anArray. Be aware the parameter is a symbol, not a string. To convert a string into a symbol use the message asSymbol. Georh Georg Heeg eK, Dortmund und Köthen, HR Dortmund A 12812 Tel. +49-3496-214328, Fax +49-3496-214712 > -----Ursprüngliche Nachricht----- > Von: Stefano Franchi [mailto:[hidden email]] > Gesendet: Sonntag, 18. März 2007 00:50 > An: vwnc > Cc: Stefano Franchi > Betreff: Selectors as variables? > > Given Smalltalk's almost infinite reflection capabilities, I assumed it > must be trivial to pass to a method a selector in its calling > parameters, but I cannot figure out how to do it. Suppose I have a > method like" > > fooClass>>doSomething: withThisMethod > anObject withThisMethod > > > withThisMethod is passed to the the method doSomething as a string and > must be converted to a selector in the method's body. How can I do > that? > > Or I may be trying to solve my problem the wrong way. Perhaps the best > way to approach this issue is to pass a block of code instead? > > > Thanks for the help. > > Stefano > > > > > __________________________________________________ > Stefano Franchi > Department of Philosophy Ph: (64) 9 373-7599 x83940 > University Of Auckland Fax: (64) 9 373-8768 > Private Bag 92019 [hidden email] > Auckland > New Zealand |
In reply to this post by stefano-franchi
Stefano
>fooClass>>doSomething: withThisMethod >anObject withThisMethod If you pass in the selector, then: doSomething: aSymbol anObject perform: aSymbol And So It Goes Sames ______________________________________________________________________ Samuel S. Shuster [|] VisualWorks Engineering, GUI Project Smalltalk Enables Success -- What Are YOU Using? |
In reply to this post by stefano-franchi
Technically, yes, but practically one is much better off passing a block instead. |
Passing a block is more powerful but might
be more complicated because 'fooClass' would never know in which context a block
is going to be performed. In 'perform' case it is always clear that selector
will be performed in 'anObject' context.
For beginners I would recommend to start
exploring 'perform' case and if it is not enough, try to use
blocks.
Regards,
Alex
|
Not sure what you mean by context here, could you elaborate?
Foo>>doSomething: aBlock
aBlock value: myInstVar
aFoo doSomething: [:v | v inspect]
versus,
Foo>>doSomething: aSelector
myInstVar perform: aSelector
aFoo doSomething: #inspect
Using perform's leads to brittle code as they are not subject to refactorings (method renames, rewrites and such), runtime packager has no way to trace them, code highligter doesn't know what they are etc.
Cheers!
-Boris -- +1.604.689.0322 DeepCove Labs Ltd. 4th floor 595 Howe Street Vancouver, Canada V6C 2T5 [hidden email] CONFIDENTIALITY NOTICE This email is intended only for the persons named in the message header. Unless otherwise indicated, it contains information that is private and confidential. If you have received it in error, please notify the sender and delete the entire message including any attachments. Thank you. From: Alexander Ivanov [mailto:[hidden email]] Sent: Sun 18/03/2007 11:19 AM To: Boris Popov; [hidden email]; [hidden email] Cc: [hidden email] Subject: RE: Selectors as variables? Passing a block is more powerful but might be more complicated because 'fooClass' would never know in which context a block is going to be performed. In 'perform' case it is always clear that selector will be performed in 'anObject' context.
For beginners I would recommend to start exploring 'perform' case and if it is not enough, try to use blocks.
Regards,
Alex
|
Boris,
I meant the general case when block is not
specified directly but compiled in other context and then sent by
name.
OtherFoo>>beforeDoSomething
| block otherObject |
otherObject := 5.
block := [ :v | otherObject inspect
].
Foo new doSomething: block
Then
Foo>>doSomething: aBlock
aBlock value: myInstVar
inspects 5 instead of
myInstVar because aBlock was compiled in other context.
That is what I meant. Sorry, I gave
a hypothetical example, did not have time to invent a useful one.
Regards,
Alex
|
Wouldn't such assumption mean that all collection protocols are flawed because you could do,
#(1 2 3) do: [:ea | 5 inspect]
so one should do,
#(1 2 3) do: #inspect
There's only so much safety you can have in a language that isn't typed :)
Travis with his Symbol>>value: thing aside, not being able to rewrite code is a killer for me,
[hidden email] inspect -> [hidden email] logToTranscript
Either way, its important to know the difference and is ultimately up to a specific problem to pick a specific solution, but I'd be very cautios when recommending perform's over blocks IMHO.
Cheers!
-Boris
-- +1.604.689.0322 DeepCove Labs Ltd. 4th floor 595 Howe Street Vancouver, Canada V6C 2T5 [hidden email] CONFIDENTIALITY NOTICE This email is intended only for the persons named in the message header. Unless otherwise indicated, it contains information that is private and confidential. If you have received it in error, please notify the sender and delete the entire message including any attachments. Thank you. From: Alexander Ivanov [mailto:[hidden email]] Sent: Sun 18/03/2007 11:57 AM To: Boris Popov; [hidden email]; [hidden email] Cc: [hidden email] Subject: RE: Selectors as variables? Boris,
I meant the general case when block is not specified directly but compiled in other context and then sent by name.
OtherFoo>>beforeDoSomething
| block otherObject |
otherObject := 5.
block := [ :v | otherObject inspect ].
Foo new doSomething: block
Then
Foo>>doSomething: aBlock
aBlock value: myInstVar
inspects 5 instead of myInstVar because aBlock was compiled in other context.
That is what I meant. Sorry, I gave a hypothetical example, did not have time to invent a useful one.
Regards,
Alex
|
In reply to this post by Alexander Ivanov-2
On 18/03/07, Alexander Ivanov <[hidden email]> wrote:
> Passing a block is more powerful but might be more complicated because > 'fooClass' would never know in which context a block is going to be > performed. In 'perform' case it is always clear that selector will be > performed in 'anObject' context. > > For beginners I would recommend to start exploring 'perform' case and if it > is not enough, try to use blocks. Alexander, I do not agree at all. Sorry :-/ Using perform is a bad habit and it is one it can be a hard to get out of. I also disagree with your analysis. Using blocks retains far more contextual information than using perform. You may see where the perform happens in the debugger but figuring out where the symbol came from is much harder. I have heard many times over the years that, "well this is a special tricky case and we really just have to use perform". I have yet to see a sitation where a blocks based solution was not clearer and easier to maintain. Really, if you can, stick with using blocks. Um, IMO. Very best regards, Bruce -- Make the most of your skills - with OpenSkills http://www.openskills.org/ |
In reply to this post by Alexander Ivanov-2
Alexander Ivanov wrote:
If you want the block to do things with the argument, which is the whole point of the exercise, then you write block code that does just that. For the above the block should then be: [:v | v inspect] then there is no confusion over what is being acted on. Of course any self references in the block refer to where the block was compiled not where it is executed - which does confuse newbies. cheers Steve A
|
It is hard to say what would
be more confusing for newbies, blocks or 'perform'. From my point of
view both are not quite easy for non-smalltalkers:
[:v | v inspect] value: anObject
or
anObject
perform: #inspect
Yes, perform is bad in debugging but blocks
are less convenient if we go a little bit further.
How do you implement this:
Foo>>doSeveralActions:
actions
actions do: [ :selector |
anObject perform: selector]
Foo new
doSeveralActions: #(read write save print)
Definition is
OK:
Foo>>doSeveralActions:
actions actions do: [ :block |
block value: anObject ].
But what about call?
blocks :=
OrderedCollection new
add: [ :v | v read
];
add: [ :v | v write
];
add: [ :v | v save
];
add: [ :v | v
print];
yourself. Foo new doSeveralActions:
blocks.
If somebody find something less ugly, I will switch to
blocks too.
Regards,
Alex
Alex Ivanov -----Original
Message-----
From: Steve Aldred [mailto:[hidden email]] Sent: Sunday, March 18, 2007 8:22 PM To: vwnc Subject: Re: Selectors as variables? Alexander Ivanov wrote:If you want the block to do things with the argument, which is the whole point of the exercise, then you write block code that does just that. For the above the block should then be: |
Oh, but examples do matter. This specific case becomes,
anObject read; write; save; print
It all comes down to code readability and maintainability (my pet peeve with selectors). (Arrays of) selectors do have their place, but its over at http://c2.com/xp/CodeSmell.html IMHO, because one sacrifices way more than one gains. I'd hate to do a method rename and leave out all the tricky places where #print wasn't an actual method send. I've spent way too much time around code that synthesized selectors to do #perform's later, imagine (self perform: 'get' , aVariableName) and multiply that by 1,000 to scratch the surface of the kinds of problems that results in. There's enough tricky problems in today's software that occupy our precious brain cycles to introduce solutions that are known uncertainty magnets. Just my .02c, I'm open to better examples to earn my support.
Cheers!
-Boris -- +1.604.689.0322 DeepCove Labs Ltd. 4th floor 595 Howe Street Vancouver, Canada V6C 2T5 [hidden email] CONFIDENTIALITY NOTICE This email is intended only for the persons named in the message header. Unless otherwise indicated, it contains information that is private and confidential. If you have received it in error, please notify the sender and delete the entire message including any attachments. Thank you. From: Alexander Ivanov [mailto:[hidden email]] Sent: Sun 18/03/2007 9:36 PM To: Steve Aldred; vwnc Subject: RE: Selectors as variables? It is hard to say what would be more confusing for newbies, blocks or 'perform'. From my point of view both are not quite easy for non-smalltalkers:
[:v | v inspect] value: anObject
or
anObject perform: #inspect
Yes, perform is bad in debugging but blocks are less convenient if we go a little bit further.
How do you implement this:
Foo>>doSeveralActions: actions
actions do: [ :selector | anObject perform: selector]
Foo new doSeveralActions: #(read write save print)
Definition is OK:
Foo>>doSeveralActions: actions actions do: [ :block | block value: anObject ].
But what about call?
blocks := OrderedCollection new
add: [ :v | v read ];
add: [ :v | v write ];
add: [ :v | v save ];
add: [ :v | v print];
yourself. Foo new doSeveralActions: blocks.
If somebody find something less ugly, I will switch to blocks too.
Regards,
Alex
Alex Ivanov -----Original Message-----
From: Steve Aldred [mailto:[hidden email]] Sent: Sunday, March 18, 2007 8:22 PM To: vwnc Subject: Re: Selectors as variables? Alexander Ivanov wrote:If you want the block to do things with the argument, which is the whole point of the exercise, then you write block code that does just that. For the above the block should then be: |
"This
specific case becomes,
anObject read; write; save;
print."...
And
then we are renaming method 'doSomething' to
'doReadWriteSavePrint' :-). The problem is Foo does not know this list at
compile time.
As for maintenance, I agree with you.
Perform is bad guy.
Alex
-----Original Message----- From: Boris Popov [mailto:[hidden email]] Sent: Sunday, March 18, 2007 9:54 PM To: Alexander Ivanov; Steve Aldred; vwnc Subject: RE: Selectors as variables?
|
In reply to this post by Alexander Ivanov-2
> Definition is OK: > > Foo>>doSeveralActions: actions > actions do: [ :block | block value: anObject ]. > > But what about call? > > blocks := OrderedCollection new > add: [ :v | v read ]; > add: [ :v | v write ]; > add: [ :v | v save ]; > add: [ :v | v print]; > yourself. > Foo new doSeveralActions: blocks. > > If somebody find something less ugly, I will switch to blocks too. implement #, on BlockClosure. Foo new doSeveralActions: [ :v | v read ], [ :v | v write ], [ :v | v save ], [ :v | v print]. One of my gripes with Smalltalk is that block syntax is not considered to be a literal, I would love to be able to write stuff like: actions := #( [ :v | v read ] [ :v | v write ] [ :v | v save ] [ :v | v print] ). R - |
Reinout:
Just tried it while finishing my morning scone and Starbucks triple shot grande latte. In anycase you can achieve what you want by using BraceContructors. If using BraceContructors it should go as follows: actions := { [ :v | v read ]. [ :v | v write ]. [ :v | v save ]. [ :v | v print]. } I find the syntax quite reasonable. I must admit to using BraceConstructors quite a bit. hth :) -Charles On Mon, 19 Mar 2007 04:19:27 -0500, Reinout Heeck <[hidden email]> wrote: > >> Definition is OK: >> Foo>>doSeveralActions: actions >> actions do: [ :block | block value: anObject ]. >> But what about call? >> blocks := OrderedCollection new >> add: [ :v | v read ]; >> add: [ :v | v write ]; >> add: [ :v | v save ]; >> add: [ :v | v print]; >> yourself. >> Foo new doSeveralActions: blocks. >> If somebody find something less ugly, I will switch to blocks too. > Trivial: > implement #, on BlockClosure. > > Foo new > doSeveralActions: [ :v | v read ], [ :v | v write ], [ :v | v save ], > [ :v | v print]. > > > > One of my gripes with Smalltalk is that block syntax is not considered > to be a literal, I would love to be able to write stuff like: > > actions := #( [ :v | v read ] [ :v | v write ] [ :v | v save ] [ :v | v > print] ). > > R > - -- Charles A. Monteiro http://wiki.nycsmalltalk.org http://www.monteirosfusion.com http://monteirofusion.blogspot.com |
In reply to this post by Reinout Heeck-2
On Mar 19, 2007, at 2:19, Reinout Heeck wrote:
Hmm.... I think if I were doing this, I'd be more inclined to implement: BlockClosure>>, aBlockClosure "Return a new block which will evaluate the receiver and then the argument in order" ^[self value. aBlockClosureValue] Just because, I don't know, it seems cool to make them recursive structures using themselves and be able to have it be uniform (i.e. the API remains value). -- Travis Griggs Objologist "There are a thousand hacking at the branches of evil to one who is striking at the root" - Henry David Thoreau |
In reply to this post by stefano-franchi
On Mar 17, 2007, at 16:50, Stefano Franchi wrote:
Stefano, I see you got your answers eventually (perform: and variants). And I hope that the discussion that followed about not confusing a beginner was not too confusing. I know it was for me. Both techniques have their place. With much cross over. They are both used _extensively_ throughout the system itself, so I think that neither can be all that bad. Without knowing what more of your code is trying to solve, it would probably be wrong of us to try and really steer you to use one technique or the other. The cool thing about Smalltalk is that it is so open to explore what solution is best for you, to refine your own guidelines as you go. -- Travis Griggs Objologist One man's blue plane is another man's pink plane. |
On 19/03/07, Travis Griggs <[hidden email]> wrote:
> Both techniques have their place. With much cross over. They are both used > _extensively_ throughout the system itself, so I think that neither can be > all that bad. Really? Can you point to an example in the base VisualWorks system where, in your view, it was more appropriate to use a perform than use a block? All the best, Bruce -- Make the most of your skills - with OpenSkills http://www.openskills.org/ |
Bruce,
The most predominant examples are in the UI. Most actions in menu specifications are symbols as well as aspects. They all are sent by perform: Georg Georg Heeg eK, Dortmund und Köthen, HR Dortmund A 12812 Tel. +49-3496-214328, Fax +49-3496-214712 > -----Ursprüngliche Nachricht----- > Von: Bruce Badger [mailto:[hidden email]] > Gesendet: Montag, 19. März 2007 16:34 > An: Travis Griggs > Cc: vwnc > Betreff: Re: Selectors as variables? > > On 19/03/07, Travis Griggs <[hidden email]> wrote: > > Both techniques have their place. With much cross over. They are both > used > > _extensively_ throughout the system itself, so I think that neither can > be > > all that bad. > > Really? Can you point to an example in the base VisualWorks system > where, in your view, it was more appropriate to use a perform than use > a block? > > All the best, > Bruce > -- > Make the most of your skills - with OpenSkills > http://www.openskills.org/ |
Free forum by Nabble | Edit this page |