Hi all,
I was looking at the implementation of some of the flow control methods and I have a question with the method whileTrue. First of all, I can see two identical implementation in the classes BlockClosure and BlockContext the implementation is this 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] I'm assuming here that there's another class Block I'm missing (something like the literal block mentioned in the comment) which is the one that contains the logic I was looking for. But I'm not able to find any other whileTrue method in my image. What's the difference between BlockClosure and BlockContext? Thanks, Erlis _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
On 04.10.2011, at 17:58, Erlis Vidal wrote: Hi all, "Block" is just short for either BlockClosure or BlockContext. "Literal" blocks are those written directly with square brackets. If you store a block in a variable and pass that variable, the block would not be literal. What's the difference between BlockClosure and BlockContext? BlockClosures are BlockContexts Done Right. If you wrote square brackets in older Squeak versions (3.x) you would get a BlockContext. In a current Squeak you get a BlockClosure. So since now we only have closures, the difference is only of historic interest. You can do some things with closures that you couldn't do with block contexts, e.g. recursive blocks: | fac | fac := nil. fac := [:n | n > 1 ifTrue: [n * (fac value: n - 1)] ifFalse: [1]]. fac value: 10 This would not have worked with contexts. - Bert - _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Hi Bert,
Thanks for your answer, it clarifies some issues but I'm still confused about the logic I've found in the whileTrue method. For example, I don't know the answers to the following questions: Can I add methods to literal blocks? Where do I implement those methods? In case your answer is in BlockClosures, why I don't see any ifTrue: in the while implementation? Thanks once again Erlis On Tue, Oct 4, 2011 at 12:22 PM, Bert Freudenberg <[hidden email]> wrote:
_______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
On 04.10.2011, at 18:41, Erlis Vidal wrote: Can I add methods to literal blocks? Yes. Where do I implement those methods? In case your answer is in BlockClosures, why I don't see any ifTrue: in the while implementation? Because the compiler generates a jump byte code for whileTrue: directly. In a browser on the whileTrue: method, click the "source" button to switch to showing byte codes. - Bert - _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Thanks Bert!
The byte code has the answer, I thought that the byte code will map the source code but I see that's not the case, probably to ensure some optimizations.. or to do that "jump" I don't know how to do that in smalltalk Thanks a lot for taking the time to answer such a newbie question. Erlis On Tue, Oct 4, 2011 at 12:57 PM, Bert Freudenberg <[hidden email]> wrote:
_______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
On 04.10.2011, at 19:16, Erlis Vidal wrote:
> Thanks Bert! > > The byte code has the answer, I thought that the byte code will map the source code but I see that's not the case, probably to ensure some optimizations.. or to do that "jump" I don't know how to do that in smalltalk For ifTrue: it is purely an optimization, yes. It would work fine by actually sending that message. It would just be slower. In the case of whileTrue:, however, it's not just an optimization. The only way to do loops otherwise would be by recursion. But the Squeak VM does not do tail-call elimination, so it would run out of space pretty soon. Generating the loop as a byte code back jump is essential for the system to work. - Bert - _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Bert Freudenberg <bert <at> freudenbergs.de> writes:
> > On 04.10.2011, at 19:16, Erlis Vidal wrote: > > > Thanks Bert! > > > > The byte code has the answer, I thought that the byte code will map the source code but I see that's not the > case, probably to ensure some optimizations.. or to do that "jump" I don't know how to do that in smalltalk > > For ifTrue: it is purely an optimization, yes. It would work fine by actually sending that message. It would > just be slower. > > In the case of whileTrue:, however, it's not just an optimization. The only way to do loops otherwise would > be by recursion. But the Squeak VM does not do tail-call elimination, so it would run out of space pretty > soon. Generating the loop as a byte code back jump is essential for the system to work. > > - Bert - > Oh no, we could as well reduce stack depth to (numberOfIteration log: 2) with silly recursive code like this: Block>>tryTwiceThen: aBlock self value ifFalse: [^aBlock value]. self value ifFalse: [^aBlock value]. ^ [self value ifFalse: [^aBlock value]. self value ifFalse: [^aBlock value]. true] tryTwiceThen: [^aBlock value] Block>>log2WhileTrue ^self tryTwiceThen: [^nil] | i maxDepth sender | i := maxDepth := 0. [i := i+1. depth := 0. sender := thisContext. [(sender := sender sender) isNil] whileFalse: [depth := depth+1]. maxDepth := maxDepth max: depth. i<10000] log2WhileTrue. ^maxDepth Nicolas _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
On 05.10.2011, at 00:24, nicolas cellier wrote:
> Bert Freudenberg <bert <at> freudenbergs.de> writes: > On 04.10.2011, at 19:16, Erlis Vidal wrote: >> >>> Thanks Bert! >>> >>> The byte code has the answer, I thought that the byte code will map the > source code but I see that's not the >> case, probably to ensure some optimizations.. or to do that "jump" I don't > know how to do that in smalltalk >> >> For ifTrue: it is purely an optimization, yes. It would work fine by actually > sending that message. It would >> just be slower. >> >> In the case of whileTrue:, however, it's not just an optimization. The only > way to do loops otherwise would >> be by recursion. But the Squeak VM does not do tail-call elimination, so it > would run out of space pretty >> soon. Generating the loop as a byte code back jump is essential for the system > to work. >> >> - Bert - >> > > > Oh no, we could as well reduce stack depth to (numberOfIteration log: 2) with > silly recursive code like this: > > > Block>>tryTwiceThen: aBlock > self value ifFalse: [^aBlock value]. > self value ifFalse: [^aBlock value]. > ^ > [self value ifFalse: [^aBlock value]. > self value ifFalse: [^aBlock value]. > true] > tryTwiceThen: [^aBlock value] > > Block>>log2WhileTrue > ^self tryTwiceThen: [^nil] > > | i maxDepth sender | > i := maxDepth := 0. > [i := i+1. > depth := 0. > sender := thisContext. > [(sender := sender sender) isNil] whileFalse: [depth := depth+1]. > maxDepth := maxDepth max: depth. > i<10000] log2WhileTrue. > ^maxDepth Yes, but log(n) is still not good enough for loops that run forever. Like the Morphic main loop. Or the idle process. I don't think it's possible to emulate whileTrue without reaching for the meta hammer. Interesting discussion though. Maybe a bit over the head of the average newbie ;) - Bert - _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Bert Freudenberg <bert <at> freudenbergs.de> writes:
> > On 05.10.2011, at 00:24, nicolas cellier wrote: > snip... gmane is a tyrant > > Yes, but log(n) is still not good enough for loops that run forever. Like the Morphic main loop. Or the idle process. > > I don't think it's possible to emulate whileTrue without reaching for the meta hammer. Interesting > discussion though. Maybe a bit over the head of the average newbie ;) > > - Bert - > Ah yes of course, this is the essential case... And we cannot even know if the loop is going to halt. For the two specific cases you submitted, we could cheat by using another VM magic and let the UI and idle process regenerate by forking themselves and completely ignore any synchronisation requirement. Or emulate tail call elimination by playing with thisContext>>sender: But the sport is becoming a bit crooked. And we're getting far from initial question. It's already something to know that a jump bytecode solves these problems efficiently. Nicolas _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
is there any reason why smalltalk doesn't implement tail recursion optimization? Is by "language design"? It tries to avoid any issue?
Thanks Erlis On Wed, Oct 5, 2011 at 1:50 PM, nicolas cellier <[hidden email]> wrote:
_______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Great explanation here:
http://gbracha.blogspot.com/2009/12/chased-by-ones-own-tail.html Read the comments as well. On Wed, Oct 5, 2011 at 12:56 PM, Erlis Vidal <[hidden email]> wrote: > is there any reason why smalltalk doesn't implement tail recursion > optimization? Is by "language design"? It tries to avoid any issue? > > Thanks > Erlis > > On Wed, Oct 5, 2011 at 1:50 PM, nicolas cellier > <[hidden email]> wrote: >> >> Bert Freudenberg <bert <at> freudenbergs.de> writes: >> >> > >> > On 05.10.2011, at 00:24, nicolas cellier wrote: >> > >> snip... gmane is a tyrant >> > >> > Yes, but log(n) is still not good enough for loops that run forever. >> > Like the >> Morphic main loop. Or the idle process. >> > >> > I don't think it's possible to emulate whileTrue without reaching for >> > the meta >> hammer. Interesting >> > discussion though. Maybe a bit over the head of the average newbie ;) >> > >> > - Bert - >> > >> >> Ah yes of course, this is the essential case... And we cannot even know if >> the >> loop is going to halt. >> For the two specific cases you submitted, we could cheat by using another >> VM >> magic and let the UI and idle process regenerate by forking themselves and >> completely ignore any synchronisation requirement. >> Or emulate tail call elimination by playing with thisContext>>sender: >> But the sport is becoming a bit crooked. And we're getting far from >> initial >> question. >> It's already something to know that a jump bytecode solves these problems >> efficiently. >> >> Nicolas >> >> _______________________________________________ >> Beginners mailing list >> [hidden email] >> http://lists.squeakfoundation.org/mailman/listinfo/beginners > > > _______________________________________________ > Beginners mailing list > [hidden email] > http://lists.squeakfoundation.org/mailman/listinfo/beginners > > Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
In reply to this post by Bert Freudenberg
On Wed, Oct 5, 2011 at 4:05 PM, Bert Freudenberg <[hidden email]> wrote:
> On 05.10.2011, at 00:24, nicolas cellier wrote: > >> Bert Freudenberg <bert <at> freudenbergs.de> writes: >> On 04.10.2011, at 19:16, Erlis Vidal wrote: >>> >>>> Thanks Bert! >>>> >>>> The byte code has the answer, I thought that the byte code will map the >> source code but I see that's not the >>> case, probably to ensure some optimizations.. or to do that "jump" I don't >> know how to do that in smalltalk >>> >>> For ifTrue: it is purely an optimization, yes. It would work fine by actually >> sending that message. It would >>> just be slower. >>> >>> In the case of whileTrue:, however, it's not just an optimization. The only >> way to do loops otherwise would >>> be by recursion. But the Squeak VM does not do tail-call elimination, so it >> would run out of space pretty >>> soon. Generating the loop as a byte code back jump is essential for the system >> to work. >>> >>> - Bert - >>> >> >> >> Oh no, we could as well reduce stack depth to (numberOfIteration log: 2) with >> silly recursive code like this: >> >> >> Block>>tryTwiceThen: aBlock >> self value ifFalse: [^aBlock value]. >> self value ifFalse: [^aBlock value]. >> ^ >> [self value ifFalse: [^aBlock value]. >> self value ifFalse: [^aBlock value]. >> true] >> tryTwiceThen: [^aBlock value] >> >> Block>>log2WhileTrue >> ^self tryTwiceThen: [^nil] >> >> | i maxDepth sender | >> i := maxDepth := 0. >> [i := i+1. >> depth := 0. >> sender := thisContext. >> [(sender := sender sender) isNil] whileFalse: [depth := depth+1]. >> maxDepth := maxDepth max: depth. >> i<10000] log2WhileTrue. >> ^maxDepth > > Yes, but log(n) is still not good enough for loops that run forever. Like the Morphic main loop. Or the idle process. > > I don't think it's possible to emulate whileTrue without reaching for the meta hammer. Interesting discussion though. Maybe a bit over the head of the average newbie ;) > > - Bert - But this kind of thread is also one of the reasons I like the Squeak community. Newbies get right to the core with their questions and there is little hierarchy. Karl _______________________________________________ Beginners mailing list [hidden email] http://lists.squeakfoundation.org/mailman/listinfo/beginners |
Free forum by Nabble | Edit this page |