Cuis problem with blocks

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

Cuis problem with blocks

Phil B
I'm attempting to get some code running on Cuis 2.0 and am having a  
problem with some pretty simple blocks like:

[:sum :ea | sum := sum + ea] value: 1 value: 2.

resulting in an error:

[:sum :ea |  Cannot store into ->sum := sum + ea] value: 1 value: 2.

However, this example works without a problem in both 3.10.2 as well  
as 3.7.  Any idea what's going on?

Thanks,
Phil

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Nicolas Cellier
Writing to block arguments is considered bad practice.
In most Smalltalk (all?), you cannot write method arguments.
Since blocks are proper closures (introduced in Cuis 2.0) same rule
now apply to block arguments.
In squeak trunk, this behavior is driven by a Preferences, you can ask
Juan if he applied same policy in Cuis.

Anyway, [:sum :ea | sum := sum + ea] is completely useless since the
variable sum cease to exist once the block closure finish execution.
It has exactly same effect as [:sum :ea | sum + ea].

This pattern was the result of some bad understanding of block return
value and particularly the way inject:into: works, even in the
pre-closure world.

Cheers

Nicolas

2010/1/21 Phil (list) <[hidden email]>:

> I'm attempting to get some code running on Cuis 2.0 and am having a problem
> with some pretty simple blocks like:
>
> [:sum :ea | sum := sum + ea] value: 1 value: 2.
>
> resulting in an error:
>
> [:sum :ea |  Cannot store into ->sum := sum + ea] value: 1 value: 2.
>
> However, this example works without a problem in both 3.10.2 as well as 3.7.
>  Any idea what's going on?
>
> Thanks,
> Phil
>
>

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Juan Vuletich-4
Thanks, Nicolas. You're right. I did include the preference in Cuis. By
default it is set not to allow assignment to block args. I recompiled
the whole system this way, removing any block arg assgnment left. I see
no reason to allow them, but the preference is there if someone needs it.

Cheers,
Juan Vuletich

Nicolas Cellier wrote:

> Writing to block arguments is considered bad practice.
> In most Smalltalk (all?), you cannot write method arguments.
> Since blocks are proper closures (introduced in Cuis 2.0) same rule
> now apply to block arguments.
> In squeak trunk, this behavior is driven by a Preferences, you can ask
> Juan if he applied same policy in Cuis.
>
> Anyway, [:sum :ea | sum := sum + ea] is completely useless since the
> variable sum cease to exist once the block closure finish execution.
> It has exactly same effect as [:sum :ea | sum + ea].
>
> This pattern was the result of some bad understanding of block return
> value and particularly the way inject:into: works, even in the
> pre-closure world.
>
> Cheers
>
> Nicolas
>
> 2010/1/21 Phil (list) <[hidden email]>:
>  
>> I'm attempting to get some code running on Cuis 2.0 and am having a problem
>> with some pretty simple blocks like:
>>
>> [:sum :ea | sum := sum + ea] value: 1 value: 2.
>>
>> resulting in an error:
>>
>> [:sum :ea |  Cannot store into ->sum := sum + ea] value: 1 value: 2.
>>
>> However, this example works without a problem in both 3.10.2 as well as 3.7.
>>  Any idea what's going on?
>>
>> Thanks,
>> Phil
>>
>>    


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Phil B
Nicolas/Juan,

Thanks for the info and that makes sense.  Yes, my example was pulled  
from some inject:into: code that was now failing and I managed to fall  
into the bad practice of using this pattern as a result of seeing  
several examples that used it.  It's not a problem changing my code as  
I'd rather do that than continue relying on the old/bad behavior, I  
was just surprised by the error.  Now I understand why I was seeing it.

Thanks again,
Phil

On Jan 21, 2010, at 7:33 AM, Juan Vuletich wrote:

> Thanks, Nicolas. You're right. I did include the preference in Cuis.  
> By default it is set not to allow assignment to block args. I  
> recompiled the whole system this way, removing any block arg  
> assgnment left. I see no reason to allow them, but the preference is  
> there if someone needs it.
>
> Cheers,
> Juan Vuletich
>
> Nicolas Cellier wrote:
>> Writing to block arguments is considered bad practice.
>> In most Smalltalk (all?), you cannot write method arguments.
>> Since blocks are proper closures (introduced in Cuis 2.0) same rule
>> now apply to block arguments.
>> In squeak trunk, this behavior is driven by a Preferences, you can  
>> ask
>> Juan if he applied same policy in Cuis.
>>
>> Anyway, [:sum :ea | sum := sum + ea] is completely useless since the
>> variable sum cease to exist once the block closure finish execution.
>> It has exactly same effect as [:sum :ea | sum + ea].
>>
>> This pattern was the result of some bad understanding of block return
>> value and particularly the way inject:into: works, even in the
>> pre-closure world.
>>
>> Cheers
>>
>> Nicolas
>>
>> 2010/1/21 Phil (list) <[hidden email]>:
>>
>>> I'm attempting to get some code running on Cuis 2.0 and am having  
>>> a problem
>>> with some pretty simple blocks like:
>>>
>>> [:sum :ea | sum := sum + ea] value: 1 value: 2.
>>>
>>> resulting in an error:
>>>
>>> [:sum :ea |  Cannot store into ->sum := sum + ea] value: 1 value: 2.
>>>
>>> However, this example works without a problem in both 3.10.2 as  
>>> well as 3.7.
>>> Any idea what's going on?
>>>
>>> Thanks,
>>> Phil
>>>
>>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Randal L. Schwartz
>>>>> "Phil" == Phil (list) <[hidden email]> writes:

Phil>   Yes, my example was pulled from some inject:into: code that was now
Phil> failing and I managed to fall into the bad practice of using this
Phil> pattern as a result of seeing several examples that used it.

Where are these "several examples" of people writing into temps/locals
so that I can steer people away from misguided advice?

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Phil B
On Jan 21, 2010, at 11:17 AM, Randal L. Schwartz wrote:

>>>>>> "Phil" == Phil (list) <[hidden email]> writes:
>
> Phil>   Yes, my example was pulled from some inject:into: code that  
> was now
> Phil> failing and I managed to fall into the bad practice of using  
> this
> Phil> pattern as a result of seeing several examples that used it.
>
> Where are these "several examples" of people writing into temps/locals
> so that I can steer people away from misguided advice?
>

Randal,

Off the top of my head, I don't recall specifically where I picked up  
this bad habit.  I do remember that early on I was having some  
problems with google queries sending me to old/obsolete versions of  
Squeak related web pages (which I didn't realize at the time) so it's  
entirely possible that this was where I picked it up as I had several  
issues being directed to outdated packages etc. and I could have  
learned it by looking at some older code that had since been corrected.

I just poked around one of my 3.10.2 images and only see this pattern  
used in a couple of places (SMSqueakMap>>check,  
KadamaVectorizer>>traverseMessage:in:firstPlayer:inCondition:,  
HostFont>>widthOfString:from:to:) though these weren't places I  
remember poking around early on, so I doubt that's how I picked it up.

Thanks,
Phil

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Cuis problem with blocks

Eliot Miranda-2
In reply to this post by Juan Vuletich-4


On Thu, Jan 21, 2010 at 4:33 AM, Juan Vuletich <[hidden email]> wrote:
Thanks, Nicolas. You're right. I did include the preference in Cuis. By default it is set not to allow assignment to block args. I recompiled the whole system this way, removing any block arg assgnment left. I see no reason to allow them, but the preference is there if someone needs it.

Agreed.  I put in the preference for cases such as loading packages containing assignments to block temps.  Without the preference it is additional work to load the package (unpacking the .mcz by hand and editing the source file).  Once the package is loaded one can hunt down and rewrite those assignments.  But how does one find them other than by resetting the preference and recompiling the package?  And how does one find block argument assignments lurking in unpackaged code save recompiling the entire system?  One abuses MessageNotUnderstood, that's how.  Here's a hack implementation of SystemNavigation allBlockArgumentAssignations.  It has just found 35 such abominations in my development image (shock, horror).  Change set attached.  Code in all its syntax coloured glory below.  Enjoy.

SystemNavigation methods for query 
allBlockArgumentAssignations 
        
"Answer all methods containing an assignment to a block argument." 
        
"SystemNavigation default 
                 browseMessageList: SystemNavigation default allBlockArgumentAssignations asSortedCollection 
                 name: 'Assignments to block arguments'"
 
        
^self allMethodsSelect: 
                 [:
m| | d assignsToBlockArg scanner | 
                 
assignsToBlockArg := false
                 
(d := m blockpcsToBlockExtents) size >= 2 ifTrue: 
                          
[scanner := InstructionStream on: m
                          
d keysDo: 
                                   
[:interval| | nArgs | 
                                   
(interval first ~= m initialPC 
                                    
and: [(nArgs := m argumentCountForBlockAtPC: interval first) > 0]) ifTrue: 
                                            
[scanner pc: interval first
                                            
[scanner pc <= interval last] whileTrue: 
                                                     
[[scanner interpretNextInstructionFor: nil] 
                                                              
on: MessageNotUnderstood 
                                                              
do: [:ex| 
                                                                       
((#(popIntoTemporaryVariable: 
                                                                                
storeIntoTemporaryVariable:includes: ex message selector) 
                                                                       
and: [ex message arguments first + 1 <= nArgs]) ifTrue: 
                                                                                
[assignsToBlockArg := true]]]]]]
                          
assignsToBlockArg

CompiledMethod methods for debugger support 
argumentCountForBlockAtPC: 
blockStartPC 
        
"Answer the argument count of the block whose first bytecode is startpc." 
        (
self pcPreviousTo: blockStartPCifNotNil: 
                 [:
closureCreationPC| 
                 
[(InstructionStream on: self) 
                          
pc: closureCreationPC
                          
interpretNextInstructionFor: nil] 
                          
on: MessageNotUnderstood 
                          
do: [:ex| 
                                   
ex message selector == #pushClosureCopyNumCopiedValues:numArgs:blockSize: ifTrue: 
                                            
[^ex message arguments at: 2]]]. 
        
self error: 'pc is not a block start pc' 

blockpcsToBlockExtents 
        
"Answer a Dictionary of (Interval from startpc to lastpc) to (Interval of blockExtent), 
         for the method and any blocks within it, using the identical numbering scheme described 
         in and orchestrated by BlockNode>>analyseArguments:temporaries:rootNode:. 
         This is a variation on startpcsToBlockExtents whcih only answers startpc to interval."
 
        
| index |
        
index := 0
        
^self 
                 
blockRangesAndExtentsInto: Dictionary new 
                 
from: self initialPC 
                 
to: self endPC 
                 
scanner: (InstructionStream on: self
                 
numberer: [| value | value := indexindex := index + 2value

blockRangesAndExtentsInto: 
aDictionary from: initialPC to: endPC scanner: scanner numberer: numbererBlock 
        
"Support routine for blockpcsToBlockExtents" 
        
| extentStart blockSizeOrLocator | 
        
self flag: 'belongs in DebuggerMethodMap'
        
extentStart := numbererBlock value
        [
scanner pc <= endPCwhileTrue: 
                 [
blockSizeOrLocator := scanner interpretNextInstructionFor: BlockStartLocator new
                  
blockSizeOrLocator isInteger ifTrue: 
                          
[self 
                                   
blockRangesAndExtentsInto: aDictionary 
                                   
from: scanner pc 
                                   
to: scanner pc + blockSizeOrLocator - 1 
                                   
scanner: scanner 
                                   
numberer: numbererBlock]]. 
        
aDictionary at: (initialPC to: endPCput: (extentStart to: numbererBlock value). 
        
^aDictionary

p.s. its my birthday today.  I should be doing something useful but this was too much fun, my present to myself.


Cheers,
Juan Vuletich


Nicolas Cellier wrote:
Writing to block arguments is considered bad practice.
In most Smalltalk (all?), you cannot write method arguments.
Since blocks are proper closures (introduced in Cuis 2.0) same rule
now apply to block arguments.
In squeak trunk, this behavior is driven by a Preferences, you can ask
Juan if he applied same policy in Cuis.

Anyway, [:sum :ea | sum := sum + ea] is completely useless since the
variable sum cease to exist once the block closure finish execution.
It has exactly same effect as [:sum :ea | sum + ea].

This pattern was the result of some bad understanding of block return
value and particularly the way inject:into: works, even in the
pre-closure world.

Cheers

Nicolas

2010/1/21 Phil (list) <[hidden email]>:
 
I'm attempting to get some code running on Cuis 2.0 and am having a problem
with some pretty simple blocks like:

[:sum :ea | sum := sum + ea] value: 1 value: 2.

resulting in an error:

[:sum :ea |  Cannot store into ->sum := sum + ea] value: 1 value: 2.

However, this example works without a problem in both 3.10.2 as well as 3.7.
 Any idea what's going on?

Thanks,
Phil