On Tue, 2 Jan 2001 08:10:37 -0500 "Andrew C. Greenberg" werdna@mucow.com wrote:
whileTrue: aBlock "Ordinarily compiled in-line, and therefore not overridable. This is in case the message is sent to other than a literal block. Evaluate the argument, aBlock, as long as the value of the receiver is true."
^ [self value] whileTrue: [aBlock value]
Still not getting it. Can someone explain to me how, even on these assumptions, this code can work? It seems to me that by evaluating self, we reduce the conditional to a boolean, and by evaluating aBlock, we reduce it to whatever its result would be. While this would excecute properly once, how can it then continue to properly execute the loop?
The method BlockContext>>whileTrue: as written will work IFF it was compiled with the optimization on. In this case the generated bytecodes are:
5 <70> self 6 <C9> send: value 7 <9C> jumpFalse: 13 8 <10> pushTemp: 0 9 <C9> send: value 10 <87> pop 11 <A3 F8> jumpTo: 5 13 <73> pushConstant: nil 14 <7C> returnTop
which basically says:
1. Evaluate the receiver block - "self value" at offsets 5,6 2. If the result of step 1 is false, return <nil> from the method - offsets 7,13,14 3. Evaluate the argument block - offsets 8,9,10 4. GOTO step 1 - offset 11
This has led me to wonder whether it would be better if Smalltalk had (horror of horrors) a GOTO. Since the implementation of this method depends on the fact that the optimized bytecodes emit GOTO, perhaps it would be clearer (and more robust, should someone decide to remove the compiler optimization) if it were actually written that way.
Cheers, Bob
on 1/2/01 8:49 AM, Bob Arning at arning@charm.net wrote: ...
This has led me to wonder whether it would be better if Smalltalk had (horror of horrors) a GOTO. Since the implementation of this method depends on the fact that the optimized bytecodes emit GOTO, perhaps it would be clearer (and more robust, should someone decide to remove the compiler optimization) if it were actually written that way.
A "structured" Goto is exactly how I implemented iteration, exceptions, and backtracking in Avail:
http://www.ericsworld.com/Mark/HTML/Avail.html
The process model is a little strange. Basically, most of the objects in Avail are immutable, so each nybblecode is defined in terms of taking an immutable chain of immutable contexts and producing another immutable chain of immutable contexts. A process contains a mutable variable that holds this immutable chain of contexts. Executing a process is defined as executing nybblecodes until the process stops, feeding the context chain resulting from a nybblecode into the next one. Lots of VM optimizations make normal usage of iteration as "intrinsically efficient" as Smalltalk.
The syntax is fairly plain:
[ $someLabel; Print "hello"; Restart someLabel; ]();
Alternatively, you can escape from nested blocks with the same kind of mechanism:
[ $someLabel; if 2+2=5 then [Exit someLabel;]; Print "2+2=4"; ]();
Just to clear things up, the "$_" notation declares a label, and is always at the start of the block being labeled. The label is just a declaration and initialization of a local variable (but not assignable, similar to arguments in most Smalltalks). In the expression "Exit someLabel", we are simply invoking the "Exit_" (multi)method with the immutable context found in the variable "someLabel".
Trick: If you're tired of relying on Compiler tricks in Smalltalk to implement space-efficient iteration, just do this:
... here := thisContext pc. ... thisContext pc: here. ...
It probably won't work, but it's more accurate pseudocode than the recursive version in whileTrue:.
squeak-dev@lists.squeakfoundation.org