whileTrue: implementation

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

whileTrue: implementation

hernan.wilkinson
Hi,
 when I'm teaching OO one of the most interesting subjects is the implementation of control flow structures with closures. 
 Having to implement #ifTrue: only with objects and messages produces in some students the "click" we are looking for, the "ah!" that makes them see the real difference with procedural languages and most no pure object languages (java, c#, etc).
 When teaching the execution model, I use the #whileTrue: implementation to show them that it is also possible to implement such a thing with just objects and messages. 
 The last semester to my surprise I saw that the #whileTrue: implementation in Pharo is cumbersome, at least for teaching porpoises, because it is based on the "hidden" detail that #whileTrue: is inlined, therefore never sent and its method never executed. The VisualWorks implementation is clearer because it is a recursive implementation that seems to work without knowing that #whileTrue: is inlined (and has a nice comment that explains that implementation detail).
 Anyway, just for teaching porpoises I thought that providing another implementation would be nice, an implementation based on the execution context, an implementation completely based on objects and messages. For example:

whileTrue: aBlock 

   self value ifTrue: [ 
aBlock value. 
thisContext restart ]

 I think it is an interesting example that allows the students to see how we can manipulate the execution environment from inside Smalltalk itself...
 Anyway, just a comment... not sure if it makes sense to change the implementation just because of this, but maybe putting a comment explaining this option would be nice.

 Bye,
 Hernan.


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: whileTrue: implementation

Randal L. Schwartz
>>>>> "Hernan" == Hernan Wilkinson <[hidden email]> writes:


Hernan> whileTrue: aBlock

Hernan>    self value ifTrue: [
Hernan> aBlock value.
Hernan> thisContext restart ]

That's an interesting implementation, but the current implementation
is clean, and is there only because #perform: has to be able to do it.

Maybe this definition could be added as a comment to the method though,
to show how you would do it *if* it wasn't inlined.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: whileTrue: implementation

Eliot Miranda-2


On Mon, Aug 16, 2010 at 11:28 AM, Randal L. Schwartz <[hidden email]> wrote:
>>>>> "Hernan" == Hernan Wilkinson <[hidden email]> writes:


Hernan> whileTrue: aBlock

Hernan>    self value ifTrue: [
Hernan> aBlock value.
Hernan> thisContext restart ]

That's an interesting implementation, but the current implementation
is clean, and is there only because #perform: has to be able to do it.

Forgive me for being so blunt but IMO the current implementation is a crok.  It can't possibly work in the absence of the inlining optimization in MessageNode:
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 stupidly forgot to change it in BlockClosure.  The following /can/ work without inlining (and can work as well as the inlined version if the compiler implements tail-recursion elimination): 

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 ifTrue:
[aBlock value.
 self whileTrue: aBlock]

BTW here's the VisualWorks 7.7 method.  For me it's a little too clever.

whileFalse: aBlock 
"Evaluate the argument, aBlock, as long as the value of the receiver is false."

^self value
ifFalse:
[aBlock value.
[self value] whileFalse: [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 '[...] whileFalse: [..]' form in the last line, rather than the more
concise 'self whileFalse: aBlock'. Using literal blocks for both the receiver
and the argument allows the compiler to inline #whileFalse:, which (in the
absence of type inferencing) could not be done if we were to use
'self whileFalse: aBlock'."
 
but it's accurate and does the job of turning
    | a b |
    a := [i <= j].
    b := [i := i + 1].
    a whileTrue: b
into an iterative execution.

So at the very least we should improve the comment in whileTrue: and whileFalse: to point to the compiler optimization in MessageNode and IMO the VisualWorks implementation is the best compromise between clarity and honesty given the lack of tail-recursion elimination.


best,
Eliot



Maybe this definition could be added as a comment to the method though,
to show how you would do it *if* it wasn't inlined. 

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: whileTrue: implementation

Hernan Wilkinson-3
I agree, at least change the comment...
Changing the implementation would be a winner too :-)

Hernan
PS: I meant "purposes" not "porpoises" in the original mail :-) Thanks Sean to point me that out :-)

2010/8/16 Eliot Miranda <[hidden email]>


On Mon, Aug 16, 2010 at 11:28 AM, Randal L. Schwartz <[hidden email]> wrote:
>>>>> "Hernan" == Hernan Wilkinson <[hidden email]> writes:


Hernan> whileTrue: aBlock

Hernan>    self value ifTrue: [
Hernan> aBlock value.
Hernan> thisContext restart ]

That's an interesting implementation, but the current implementation
is clean, and is there only because #perform: has to be able to do it.

Forgive me for being so blunt but IMO the current implementation is a crok.  It can't possibly work in the absence of the inlining optimization in MessageNode:
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 stupidly forgot to change it in BlockClosure.  The following /can/ work without inlining (and can work as well as the inlined version if the compiler implements tail-recursion elimination): 

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 ifTrue:
[aBlock value.
 self whileTrue: aBlock]

BTW here's the VisualWorks 7.7 method.  For me it's a little too clever.

whileFalse: aBlock 
"Evaluate the argument, aBlock, as long as the value of the receiver is false."

^self value
ifFalse:
[aBlock value.
[self value] whileFalse: [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 '[...] whileFalse: [..]' form in the last line, rather than the more
concise 'self whileFalse: aBlock'. Using literal blocks for both the receiver
and the argument allows the compiler to inline #whileFalse:, which (in the
absence of type inferencing) could not be done if we were to use
'self whileFalse: aBlock'."
 
but it's accurate and does the job of turning
    | a b |
    a := [i <= j].
    b := [i := i + 1].
    a whileTrue: b
into an iterative execution.

So at the very least we should improve the comment in whileTrue: and whileFalse: to point to the compiler optimization in MessageNode and IMO the VisualWorks implementation is the best compromise between clarity and honesty given the lack of tail-recursion elimination.


best,
Eliot



Maybe this definition could be added as a comment to the method though,
to show how you would do it *if* it wasn't inlined. 

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project



--
Hernán Wilkinson
Agile Software Development, Teaching & Coaching
Mobile: +54 - 11 - 4470 - 7207
email: [hidden email]
site: http://www.10Pines.com


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: whileTrue: implementation

Marcus Denker-4
In reply to this post by Eliot Miranda-2
I added a entry in the bugtracker for this so we don't forget:



On Aug 16, 2010, at 8:53 PM, Eliot Miranda wrote:

BTW here's the VisualWorks 7.7 method.  For me it's a little too clever.

whileFalse: aBlock 
"Evaluate the argument, aBlock, as long as the value of the receiver is false."

^self value
ifFalse:
[aBlock value.
[self value] whileFalse: [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 '[...] whileFalse: [..]' form in the last line, rather than the more
concise 'self whileFalse: aBlock'. Using literal blocks for both the receiver
and the argument allows the compiler to inline #whileFalse:, which (in the
absence of type inferencing) could not be done if we were to use
'self whileFalse: aBlock'."
 
but it's accurate and does the job of turning
    | a b |
    a := [i <= j].
    b := [i := i + 1].
    a whileTrue: b
into an iterative execution.

So at the very least we should improve the comment in whileTrue: and whileFalse: to point to the compiler optimization in MessageNode and IMO the VisualWorks implementation is the best compromise between clarity and honesty given the lack of tail-recursion elimination.

--
Marcus Denker  -- http://www.marcusdenker.de
INRIA Lille -- Nord Europe. Team RMoD.


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: whileTrue: implementation

Richard Durr-2
http://stackoverflow.com/questions/2500483/is-there-a-way-in-a-message-only-language-to-define-a-whiletrue-message-without-r

2010/8/17 Marcus Denker <[hidden email]>
I added a entry in the bugtracker for this so we don't forget:



On Aug 16, 2010, at 8:53 PM, Eliot Miranda wrote:

BTW here's the VisualWorks 7.7 method.  For me it's a little too clever.

whileFalse: aBlock 
"Evaluate the argument, aBlock, as long as the value of the receiver is false."

^self value
ifFalse:
[aBlock value.
[self value] whileFalse: [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 '[...] whileFalse: [..]' form in the last line, rather than the more
concise 'self whileFalse: aBlock'. Using literal blocks for both the receiver
and the argument allows the compiler to inline #whileFalse:, which (in the
absence of type inferencing) could not be done if we were to use
'self whileFalse: aBlock'."
 
but it's accurate and does the job of turning
    | a b |
    a := [i <= j].
    b := [i := i + 1].
    a whileTrue: b
into an iterative execution.

So at the very least we should improve the comment in whileTrue: and whileFalse: to point to the compiler optimization in MessageNode and IMO the VisualWorks implementation is the best compromise between clarity and honesty given the lack of tail-recursion elimination.

--
Marcus Denker  -- http://www.marcusdenker.de
INRIA Lille -- Nord Europe. Team RMoD.


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project