What does #while do? (Solved.) And what does `#Classname [...]` do? (Probably solved.)

While I was toying to see what syntax is “taken” and what not

// ERROR: syntax error, unexpected INTEGER, expecting NAME or CLASSNAME or WHILE or '['

I know what # does for an array (makes it immutable) and likewise #NAME enables the array-like assignment on the left-hand side.

[1, 3][1] = 5 // -> [ 1, 5 ]
#[1, 3][1] = 5
// ERROR: Primitive '_BasicPut' failed.
// Attempted write to immutable object.

#a, b = [3, 5]
a - b // -> -2

But why can while follow a #, i.e. what does #while do? (And I’m also not sure what #CLASSNAME is there for, although that might be simply a side-effect of #NAME.)

My quick look at lang11d seems to indicate it’s probably so you can use while as variable name sometimes…

name		: NAME { $$ = zzval; }
			| WHILE { $$ = zzval; }

So let’s try that:

f = {var x = 1, while = 2; x + while } // -> a Function
f.() // -> 3

g = {var x, while; #while, x = [1, 2]; [while, x] } // -> a Function
g.() -> [ 1, 2 ]

I guess it’s an interesting choice to allow while to be a “true keyword” in some contexts but a variable name in others.

Also a little discovery from the parser grammar file (this might be documented though): you can use ellipsis in “mavars” assignments… with semantics similar to [C] “varargs” for function arguments (that also also in SC for args, of course).

#x, y ... z = (1..10)
z // -> [ 3, 4, 5, 6, 7, 8, 9, 10 ]

Finally, the #CLASSNAME is actually not an offshoot of #NAME but one of #[.

listlit	: '#' '[' literallistc ']'
				{ $$ = (intptr_t)newPyrLitListNode(0, (PyrParseNode*)$3); }
		| '#' classname  '[' literallistc ']'
				{ $$ = (intptr_t)newPyrLitListNode((PyrParseNode*)$2, (PyrParseNode*)$4); }

So a valid syntax example would be

#Object [1, 2, 3]

// ERROR: Only Array is supported as literal type.
// Compiling as an Array.
// -> [ 1, 2, 3 ]

But as the error message says, while that parses, it doesn’t really work.

I guess the actual idea was to allow immutable Collections to be written like that since you can write collections by omitting a set of parentheses and “go straight for brackets”

Set[1, 2, 3] // ok

So presumably the immutable version would have been

#Set[1, 2, 3] // but that errors

In Smalltalk, control structures are only method calls. Philosophically, while is only a method selector and not a reserved keyword (though as a practical matter of optimization, while(conditionFunc, loopBody) is recognized as a flow-of-control structure and looping bytecodes are generated).

In fact, with tail call optimization, while could be implemented with only standard method dispatch (no special bytecodes):

+ Function {
    while { |body|
        if(this.value.not) { ^nil };

That would be slow, so we don’t want to get rid of the looping optimization. But the point is that there isn’t any reason why while should be regarded as a reserved keyword, except convention from other languages.


I’m pretty sure in SC while was made a keyword (in the parser sense, i.e. a token) only because of comprehensions which allow, e.g.

{:x, x<-(1..), :while 0.8.coin}.repeat(4).all

In that context (preceded by colon), while isn’t a method. It does look like it took a bit of effort in the Bison file the keep while definable in other contexts to be something else.

Actually even in the context of comprehensions you can use it as a variable, as long as it’s not prefixed by colon.

{: x*while, x while<-(1..5)}.all

And even

{:while, while<-(1..), while.odd, ::while.postln, :while while < 8}.all

is ok.