[squeak-dev] A little puzzle

Mateusz Grotek unoduetre at poczta.onet.pl
Thu May 14 22:42:51 UTC 2015


Dnia 14.05.2015 17:33:45, Stéphane Rollandin napisał(a):
> Hello all,
> 
> I'm finding myself unable to implement something seemingly simple.   
> Here is the puzzle:
> 
> I want an iterator factory which, given a specific collection,  
> produces a block taking two arguments, also blocks. One (the doBlock)  
> tells what should be done for each element of the collection, and the  
> other (the whileBlock) is a test allowing to abort the whole  
> operation.
> 
> So, something like this:
> 
> Puzzle>>blockIterating: aCollection
> 
> 	^ [:doBlock :whileBlock |
> 		aCollection do: [:i |
> 			(whileBlock value: i) ifFalse: [^ self].
> 			doBlock value: i]].
> 
> 
> Then I could do things like the following:
> 
> 
> | block |
> 
> block := Puzzle new blockIterating: (1 to: 5).
> 
> block value: [:p | Transcript show: p; cr] value: [:p | p < 3]
> 
> 
> 	
> But the above fails with a 'Block cannot return' (that's the [^ self]  
> block in the #blockIterating: method). I have attached the code; just  
> do "Puzzle new fail".
> 
> I can't find a workaround.
> 
> How should I proceed to get a working iterator block ?
> 
> Stef

The behaviour is correct. The ^ operator has lexical scope. It returns  
from the lexically enclosing method.
In this case it would return from blockIterating:, but at this point  
the method has already returned, so you cannot return from it the  
second time.

What you really want is another method. Just use two separate methods:

for: aCollection do: aDoBlock unless: aWhileBlock
  	aCollection do: [:i |
		(whileBlock value: i) ifFalse: [^ self].
  		doBlock value: i
  	]

blockIterating: aCollection
  	[:doBlock :whileBlock |
  		self for: aCollection do: doBlock while: whileBlock
	].




More information about the Squeak-dev mailing list