Block problem

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

Block problem

Ole M Halck-2
I've run into a D5 problem with blocks that I'm having trouble getting
around. A simple illustrating example is this:
In a class named MyClass, I have the following method:

testOneDigitDivisorsOf: anInteger

    | blockCollection |
    blockCollection := OrderedCollection new.
    1 to: 9 do: [:divisor |
        blockCollection add: [:number | number \\ divisor == 0]].
    ^blockCollection collect: [:block | block value: anInteger].

Now I expected "MyClass new testOneDigitDivisorsOf: 63", for example, to
return a collection with true in slots 1, 3, 7 and 9, but all of its
elements are false. Substituting 60 for 63, however, gives an all-true
reply; apparently, the value 10 held by the variable "divisor" after the
to:do: has finished is used in all the blocks. I guess this may have
something to do with the lack of full block closures or something (my
understanding of these things is pretty incomplete). Any tips on how to work
around this problem?


Reply | Threaded
Open this post in threaded view
|

Re: Block problem

Ole M Halck-2
I wrote:
> I've run into a D5 problem with blocks that I'm having trouble getting
> around. [...]

D'oh, it helps trying just a _little_ harder before crying for help... The
problem was solved simply by adding a method

testBlockFor: divisor
    ^[:number | number \\ divisor == 0]

and changing the loop in the original method to

1 to: 9 do: [:divisor | blockCollection add: (self testBlockFor: divisor)].

--
OleM


Reply | Threaded
Open this post in threaded view
|

Re: Block problem

Chris Uppal-3
In reply to this post by Ole M Halck-2
Ole M Halck wrote:

> I guess this may have
> something to do with the lack of full block closures

That's right, yes.


> Any tips on how to
> work around this problem?

If the example that you posted isn't a simplified version of real code that
depends more crucially on using Blocks, then expressing it as:

    testOneDigitDivisorsOf: anInteger
        ^ (1 to: 9) collect: [:i | anInteger \\ i == 0].

seems to do the trick. (It answers an Array rather than an OrderedCollection,
but that's easy to fix with #asOrderedCollection or similar.)

If really do need to create a collection of Blocks in a loop, then the thing to
do is to use a separate method call to create each block.  For example
(completely untested):

    testOneDigitDivisorsOf: anInteger
        | blockCollection |
        blockCollection :=  (1 to: 9) collect:
                        [:divisor | self divisorBlockFor: divisor].
        ^ blockCollection collect: [:block | block value: anInteger].

where:

    divisorBlockFor: anInteger
        ^ [:number | number \\ anInteger == 0].

    -- chris