Fear and loathing of the "perification" of Smalltalk
Paolo Bonzini
bonzini at gnu.org
Fri Sep 14 07:40:00 UTC 2007
>> but I agree with Damien that I would *not* call it a block.
> Why not? Because curly braces are implemented as a fixed kind of macro
> in Squeak? If that's the case then you're stuck with a preconception
> that is limiting your thinking.
No, because I see a Block as a single indivisible evaluation. Parallel
execution would be implemented on top of an *array of blocks*, for example.
>> BlockClosure>>#value
>> ^self blocksForEachStatement inject: nil into:
>> [ <lambda> :old :each | each value ]
>>
>> BlockClosure>>#values
>> ^self blocksForEachStatement collect: [ <lambda> :each | each
>> value ]
>>
>> LambdaBlockClosure>>#value
>> <primitive: ...>
>>
>> LambdaBlockClosure>>#values
>> ^Array with: self value
>
> Yes, one could do it that way however it's not as flexible since you're
> making the block with a "<lambda>" marker of some kind. What is the
> "<lambda>" statement doing in there precisely. Primitives don't
> currently work that way so you are suggesting further syntax changes
> too. How would that work?
It would make a "single statement" block, and it is (conjectured to be)
needed to avoid infinite recursion (notice that BlockClosure>>#value
uses blocks). In these two cases it is not necessary, because the
blocks I'm marking are also single-statement. But it is not necessarily
true that all the blocks involved in the implementation of blocks are
single statement.
>> I will even make a bold statement about performance; you could
>> implement #value via a BlockClosure>>#asLambda method and cache its
>> result; then the result would probably not even be much slower than
>> the current state of things!
>
> Ok, how do you see "asLambda" working? What do you mean by "asLambda"?
> How do you see the result of #asLambda being different from a block?
#asLambda would coalesce all the statements into a single indivisible
block-as-we-know-it-in-current-Smalltalk.
> [ a. b. c ] valuesOn: aStream
>
> Note that this level of parameterization with Blocks isn't possible with
> the curly braces syntax
Sure it is. Not that I'd endorse it.
Array>>#valuesOn:
aStream nextPutAll: (self collect: [ :each | each value ])
> [
> Object subclass: #Person.
>
> Person
> addInstanceVariable: #firstName;
> addInstanceVariable: #middleName;
> addInstanceVariable: #lastName.
>
> "Block form."
> Person addInstanceMethod: [firstName: aString | firstName := aString ].
Not so easy. How do you guarantee that "firstName" is in scope when the
block is compiled? You would have to store a parse tree for the method,
or something like that, and so far so good. But much worse, you would
have to turn *each* and *every* undefined variable appearing in a block
from a compile-time error to a run-time error a la #doesNotUnderstand:.
Because...
> "Yes, the intent is to be able to do this flexibly storing the block
> first and even using it as needed if you want."
> aBlock := [middleName: aString | middleName := aString ].
> Person addInstanceMethod: aBlock.
... there is no guarantee that a block will end up #value'd rather than
#addInstanceMethod:'ed to a class that does not even exist.
> "Yes, the intent is to be able to do this as well."
> aBlock := [:aString | lastName := aString ].
> Person addInstanceMethod: aBlock named: #lastName:.
Same here: you could also do
Animal addInstanceMethod: aBlock named: #lastName:
someCollection do: aBlock
and both of these would be errors. So, you cannot verify undefined
variables of blocks until run-time.
> No more need for legacy Smalltalk chunk format with it's weird syntax -
> it can now be depreciated!
Indeed, but you can also do that with a declarative syntax as is
implemented in Stef's Sapphire or in GST 3.0 betas.
> Part of moving a language forward is deleting
> that which isn't needed anymore. It turns out that by unifying Block and
> Method syntax we can simplify the language and eliminate unneeded
> syntax!
Are you still sure after my objection above?
> Yes, at runtime Blocks and Methods are implemented differently and there
> is little need, that I can see, to change that. This change takes place
> at the source code level for the most part.
They are more similar than you'd think. The main difference is in how
they are activated, not in how they are stored.
> Yes, a "conversion" between Block and Method needs to take place. Yes,
> it's possible not all Blocks may be able to be converted and vice versa;
> that's what exceptions are for. (I'd have to think that one through in
> detail).
That might be more or less the same problem I hinted at above.
> Yes, those are
> technical terms; for an in depth discussion on them this article is
> excellent:
Thanks, I'm reading it.
> Maybe we could collect together all "extensions" or "variants" from all
> the Smalltalk versions into one place for easy reference? Who'd be up to
> helping with that?
AFAIK, these are
{...} RHS (GNU, Squeak)
{...} LHS (old Squeak only?)
#{...} (GNU, VW)
namespaces (GNU, VW, VA, ST/X)
#[...] (all?)
##(...) (GNU, VA, Dolphin)
pragmas (many but with different implementation details)
Sorry for snipping so much of the rest, it was useful to understand your
POV but it is not something that I can "answer" or "object to"; just a note:
>> The second example is Unicode; you can force everybody to write
>> "16r1000 asCharacter" (which is also less efficient than $A) or try to
>> find a simple extension to the syntax, for example $<16r1000> could be
>> an idea.
> Or just $16r1000. Why bother with "<" and ">"?
Because $8r40 is weird but valid Smalltalk (sends r1000 to the character
8), while $<8r40> would be the same as the space character (ASCII 32).
Anyway, you see, this is a syntax extension. :-)
Paolo.
More information about the Squeak-dev
mailing list
|