It's possible that I'm just not getting it, but it would appear that the pseudo-code for #whileTrue; and #whileFalse: is incorrect. Even if I were right, it is still the height of pedantry on my part to call this a bug, since the code is never executed due to compiler inlining. Nevertheless, perhaps it would be more aesthetically pleasing to have pseudo-code here that would work if the compiler did not inline loops?
The present code in BlockContext is:
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]
But it would appear to me that this code would infinite loop for so long as these valuations do not result in a walkback. In either case the behavior appears both undefined and incorrect for most BlockContext instances and arguments. Perhaps something like the following would yield the desired result?
^ self value ifTrue: [aBlock value. self whileTrue: aBlock]
(and in the case of #whileFalse, use #ifFalse instead).
"Andrew C. Greenberg" wrote:
It's possible that I'm just not getting it, but it would appear that the pseudo-code for #whileTrue; and #whileFalse: is incorrect. Even if I were right, it is still the height of pedantry on my part to call this a bug, since the code is never executed due to compiler inlining.
For me it is a bug, since it wouldn't work without inlining literal blocks.
Nevertheless, perhaps it would be more aesthetically pleasing to have pseudo-code here that would work if the compiler did not inline loops?
The present code in BlockContext is:
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]
But it would appear to me that this code would infinite loop for so long as these valuations do not result in a walkback.
Agreed for the case of *not* inlining literal blocks.
In either case the behavior appears both undefined and incorrect for most BlockContext instances and arguments.
Here I disagree. If we are relying on inlining it should work.
Perhaps something like the following would yield the desired result?
^ self value ifTrue: [aBlock value. self whileTrue: aBlock]
(and in the case of #whileFalse, use #ifFalse instead).
This looks semantically correct for me. The only problem here is a potential stack overflow, since every evaluation of aBlock leads to a recursive call of #whileTrue:. Here a loop with a condition is realized by recursion. Probably in practice we must have compiler intelligence to avoid recursion with corresponding ST code relying on this. As an (worse) alternative we could have a primitive here.
From VisualWorks® NonCommercial, Release 5i.1 of January 24, 2000:
--- BlockClosure>> whileTrue: aBlock "Evaluate the argument, aBlock, as long as the value of the receiver is true."
^self value ifTrue: [aBlock value. [self value] whileTrue: [aBlock value]]
"This method is inlined if both the receiver and the argument are literal blocks. In all other cases, the code above is run. Note that the code above is defined recursively. However, to avoid actually building an activation record each time this method is invoked recursively, we have used the '[...] whileTrue: [..]' form in the last line, rather than the more concise 'self whileTrue: aBlock'. Using literal blocks for both the receiver and the argument allows the compiler to inline #whileTrue:, which (in the absence of type inferencing) could not be done if we were to use 'self whileTrue: aBlock'." --- This variant avoids recursion if the compiler inlines literal blocks *and* should work without inlining - though very inefficient regarding time and memory (more inefficient than Andrew's suggestion) -, too.
I vote for the VW variant.
Greetings,
Stephan
squeak-dev@lists.squeakfoundation.org