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