Who wants full block closures and why?
David N. Smith (IBM)
dnsmith at watson.ibm.com
Sat Jul 17 19:54:59 UTC 1999
At 16:29 -0700 7/15/99, Craig Latta wrote:
> I'm compiling a summary for spec/documentation purposes. (I
>also intend to implement them :)
I do! Why?
Because I use them all the time in other implementations.
Because they allow optimized blocks: you can declare local variables
inside the block, not reference anything outside the block, and not
have to save a context. (And even if you *do* save the context you
don't have problems with multiple blocks referencing the same local
variable.)
Because blocks that are not closures are ugly kludges.
Because you can pass optimized closures here and there and everywhere
else and hot have to worry about conflicts with single copy local
variables in the context.
Closures allow implementation of recursive blocks, and, yes indeed,
they are useful. Beside, why should the worlds best language have
such an ugly restriction?
Because, these days, it's not Smalltalk unless it has closures. (I
guess I must feel strongly about this! :-)
(As a non-implementer, maybe I'm giving closures properties that are
not properly due to closures, but to other problems with blocks;
regardless, they are broken!)
Non-cute example:
| blockArray dataArray |
blockArray := Array new: 5.
dataArray := #( 'Apple' 'Orange' 'Grape' 'Lemon' 'Kiwi').
1 to: blockArray size do: [ :index |
blockArray
at: index
put: [ dataArray at: index ] ].
^ (blockArray at: 2) value
In Squeak 2.4c it gets an index out of range error. (Yes, indeed! See
if you can figure out why before running it!)
Interesting to note that VW 2.5 (my most recent version) answers
'Orange', while IBM/ST 4.5 answers 'Kiwi'.
There seems to be some disagreement about when variables in a context
are bound to the block. While 'Orange' is the answer I intended, I
find the IBM/ST result more understandable since there is no tricky
binding. (But, maybe I'm just confused!) To get an answer of 'Orange'
in IBM/ST it is necessary to write the #at:put: this way:
| blockArray dataArray |
blockArray := Array new: 5.
dataArray := #( 'Apple' 'Orange' 'Grape' 'Lemon' 'Kiwi').
1 to: blockArray size do: [ :index |
blockArray
at: index
put: ([ :n |
[ dataArray at: n ]
] value: index) ].
^ (blockArray at: 2) value
At the time the #at:put: is executed, a block is evaluated, passing
index, and answering another block which has the value of index, but
not a direct reference to index.
I don't particularity care which way it works, provided that there
are simple rules that describe it, and so that one is not terribly
surprised by the results. I find the VW result confusing after some
thought since it appears to reference a local variable, but doesn't;
I find the IBM/ST code less than obvious at first, but quite clear
once I've thought about it a while.
So, how should it be?
Dave
_______________________________
David N. Smith
IBM T J Watson Research Center
Hawthorne, NY
_______________________________
Any opinions or recommendations
herein are those of the author
and not of his employer.
More information about the Squeak-dev
mailing list
|