[MacRuby] #528: Improve Tail Call Elimination
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- As it currently stands, MacRuby performs TCO for a method that calls itself. This is a great start and the implementation appears to be better than any other current Ruby implementation. When dealing with OO data structures, it's more common to call methods on _other_ instances and/or mutual recursion between two methods--be they on the same or a different instance. For example, imagine traversing a linked list recursively: def each yield(head) tail.each(&block) end This works great for small-ish lists but when processing larger lists stack overflows are common place. To remedy this, it needs to be re- written iteratively: def each list = self while !list.empty? yield(list.head) list = list.tail end end Not only is the latter more verbose, but in either case, without TCO, because the code always executes in the context of the first element, the traversal must complete before the garbage collector has a chance to reap unreferenced elements. It would be great if MacRub could do tail-call elimination for any returning statement that no longer requires the stack. -- Ticket URL: <http://www.macruby.org/trac/ticket/528> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by conradwt@…): One of the goals of using LLVM for MacRuby was to improve tail call optimization. In regards to writing recursive methods, one would usually use memoization technique(s) in conjunction with recursion to eliminate wasteful calls. Also, all core data structures or containers within Ruby Programming Language provide mechanisms for easily iterating through their contents. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:1> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Description changed by lsansonetti@…: Old description:
As it currently stands, MacRuby performs TCO for a method that calls itself. This is a great start and the implementation appears to be better than any other current Ruby implementation.
When dealing with OO data structures, it's more common to call methods on _other_ instances and/or mutual recursion between two methods--be they on the same or a different instance.
For example, imagine traversing a linked list recursively:
def each yield(head) tail.each(&block) end
This works great for small-ish lists but when processing larger lists stack overflows are common place. To remedy this, it needs to be re- written iteratively:
def each list = self while !list.empty? yield(list.head) list = list.tail end end
Not only is the latter more verbose, but in either case, without TCO, because the code always executes in the context of the first element, the traversal must complete before the garbage collector has a chance to reap unreferenced elements.
It would be great if MacRub could do tail-call elimination for any returning statement that no longer requires the stack.
New description: As it currently stands, MacRuby performs TCO for a method that calls itself. This is a great start and the implementation appears to be better than any other current Ruby implementation. When dealing with OO data structures, it's more common to call methods on _other_ instances and/or mutual recursion between two methods--be they on the same or a different instance. For example, imagine traversing a linked list recursively: {{{ def each yield(head) tail.each(&block) end }}} This works great for small-ish lists but when processing larger lists stack overflows are common place. To remedy this, it needs to be re- written iteratively: {{{ def each list = self while !list.empty? yield(list.head) list = list.tail end end }}} Not only is the latter more verbose, but in either case, without TCO, because the code always executes in the context of the first element, the traversal must complete before the garbage collector has a chance to reap unreferenced elements. It would be great if MacRub could do tail-call elimination for any returning statement that no longer requires the stack. -- -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:2> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…):
In regards to writing recursive methods, one would usually use memoization technique(s) in conjunction with recursion to eliminate wasteful calls.
I'm not worried about wasteful calls. Recursively descending through a large data structure is the problem.
Also, all core data structures or containers within Ruby Programming Language provide mechanisms for easily iterating through their contents.
Perhaps the example was misleading, these are custom application data structures with thousands of nodes. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:3> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by jvoorhis@…): Replying to [comment:3 haruki.zaemon@…]:
I'm not worried about wasteful calls. Recursively descending through a large data structure is the problem.
+1 Guy Steele made a good argument for supporting mutually recursive method calls for the same reason at http://projectfortress.sun.com/Projects/Community/blog/ObjectOrientedTailRec.... -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:4> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…):
Guy Steele made a good argument for supporting mutually recursive method calls for the same reason at http://projectfortress.sun.com/Projects/Community/blog/ObjectOrientedTailRec....
I also wrote a piece on my experience after reading Guy's article: http://www.harukizaemon.com/2009/12/why-object-oriented-language-need- tail-calls.html -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:5> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by conradwt@…): Replying to [comment:3 haruki.zaemon@…]:
In regards to writing recursive methods, one would usually use memoization technique(s) in conjunction with recursion to eliminate wasteful calls.
I'm not worried about wasteful calls. Recursively descending through a large data structure is the problem.
If you need tail call optimization, then you're definitely concerned about the wasteful calls because the goal of tail call optimization is to transform recursive alogithm into iterative algorithm. Thus, reducing the overall stack space used and approve the efficiency of the running algorithm. Memoization is a manual way of achieving this that greatly decreases stack frame usage but I guess that you're looking for something automatically done with MacRuby VM.
Also, all core data structures or containers within Ruby Programming Language provide mechanisms for easily iterating through their contents.
Perhaps the example was misleading, these are custom application data structures with thousands of nodes.
Yes, there could be thousands of nodes within your custom application data structure but it's still your requirement to implement the appropriate traversal algorithm for the data set that you're operating on. In short, one should use the best algorithm for the job and not rely so heavily on what's happening within the language's internals. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:7> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by conradwt@…): TCO would be nice to have but I feel that Ruby specs for both core and language for the MacRuby VM are the most important at this time. Also, this is an open-source project. Thus, one can feel free and receive support for working on any of the internals of the MacRuby VM. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:8> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…): Replying to [comment:7 conradwt@…]:
If you need tail call optimization, then you're definitely concerned about the wasteful calls because the goal of tail call optimization is to transform recursive alogithm into iterative algorithm.
The aim of TCO is to allow recursive algorithms to perform within a constrained stack frame. Whether you choose to implement this as re- writing the algorithm iteratively or instead throwing away the stack frame is a choice.
I guess that you're looking for something automatically done with MacRuby VM.
I don't mind if it's explicit :)
It's still your requirement to implement the appropriate traversal algorithm for the data set that you're operating on. In short, one should use the best algorithm for the job and not rely so heavily on what's happening within the language's internals.
And I have, twice: once recursively; then again iteratively actually make it perform. The former being MUCH simpler, the latter being horribly complex. I I'm not accusing MacRuby of being flawed, I'm merely suggesting that, as per the links posted, OO algorithms and data structures can be greatly improved by languages that support TCO. Yes, it's possible to write complex algorithms without TCO; it's also much easier to write them with it. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:9> MacRuby <http://macruby.org/>
I have to say - Trac seems to be a rather bad way of having architectural discussions. I've been having a hard time even understanding who says what for the last 2-3 rounds of comments. Wouldn't this be a better sort of discussion to have on the -devel mailing list, then distilling the action items (if any) into the Trac bug? Just a thought... Happy New Year everyone! - Jordan On Dec 31, 2009, at 8:23 PM, MacRuby wrote:
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+--------------------------------------
Comment(by haruki.zaemon@…):
Replying to [comment:7 conradwt@…]:
If you need tail call optimization, then you're definitely concerned about the wasteful calls because the goal of tail call optimization is to transform recursive alogithm into iterative algorithm.
The aim of TCO is to allow recursive algorithms to perform within a constrained stack frame. Whether you choose to implement this as re- writing the algorithm iteratively or instead throwing away the stack frame is a choice.
I guess that you're looking for something automatically done with MacRuby VM.
I don't mind if it's explicit :)
It's still your requirement to implement the appropriate traversal algorithm for the data set that you're operating on. In short, one should use the best algorithm for the job and not rely so heavily on what's happening within the language's internals.
And I have, twice: once recursively; then again iteratively actually make it perform. The former being MUCH simpler, the latter being horribly complex.
I I'm not accusing MacRuby of being flawed, I'm merely suggesting that, as per the links posted, OO algorithms and data structures can be greatly improved by languages that support TCO. Yes, it's possible to write complex algorithms without TCO; it's also much easier to write them with it.
-- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:9> MacRuby <http://macruby.org/>
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Jordan, I agree that this architectural discussion doesn't need to be a part of the enhancement request. -Conrad On Thu, Dec 31, 2009 at 8:39 PM, Jordan K. Hubbard <jkh@apple.com> wrote:
I have to say - Trac seems to be a rather bad way of having architectural discussions. I've been having a hard time even understanding who says what for the last 2-3 rounds of comments. Wouldn't this be a better sort of discussion to have on the -devel mailing list, then distilling the action items (if any) into the Trac bug?
Just a thought... Happy New Year everyone!
- Jordan
On Dec 31, 2009, at 8:23 PM, MacRuby wrote:
#528: Improve Tail Call Elimination
-------------------------------------+--------------------------------------
Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco
-------------------------------------+--------------------------------------
Comment(by haruki.zaemon@…):
Replying to [comment:7 conradwt@…]:
If you need tail call optimization, then you're definitely concerned about the wasteful calls because the goal of tail call optimization is to transform recursive alogithm into iterative algorithm.
The aim of TCO is to allow recursive algorithms to perform within a constrained stack frame. Whether you choose to implement this as re- writing the algorithm iteratively or instead throwing away the stack
frame
is a choice.
I guess that you're looking for something automatically done with MacRuby VM.
I don't mind if it's explicit :)
It's still your requirement to implement the appropriate traversal algorithm for the data set that you're operating on. In short, one should use the best algorithm for the job and not rely so heavily on what's happening within the language's internals.
And I have, twice: once recursively; then again iteratively actually make it perform. The former being MUCH simpler, the latter being horribly complex.
I I'm not accusing MacRuby of being flawed, I'm merely suggesting that, as per the links posted, OO algorithms and data structures can be greatly improved by languages that support TCO. Yes, it's possible to write complex algorithms without TCO; it's also much easier to write them with it.
-- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:9> MacRuby <http://macruby.org/>
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…): Replying to [comment:8 conradwt@…]:
TCO would be nice to have but I feel that Ruby specs for both core and language for the MacRuby VM are the most important at this time.
I understand and appreciate that.
Also, this is an open-source project. Thus, one can feel free and receive support for working on any of the internals of the MacRuby VM.
I'd gladly, nay enthusiastically, take a stab at it but I suspect I'd need some hand holding to get me going. I'm not sure I even know where to begin in the codebase. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:10> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…): Replying to [comment:8 conradwt@…]:
TCO would be nice to have but I feel that Ruby specs for both core and language for the MacRuby VM are the most important at this time. Also, this is an open-source project. Thus, one can feel free and receive support for working on any of the internals of the MacRuby VM.
Having looked at the code, I see the TCO stuff is all in LLVM anyway. Guess I'll throw up my hands in defeat. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:11> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…): I dug a little deeper and apparently LLVM already supports quite sophisticated TCO, including mutual recursion. Not sure why that doesn't take effect in MacRuby but I assume it's due to the way calls are constructed. Anyway, it's now well and truly outside my abilities. Thanks, Simon -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:12> MacRuby <http://macruby.org/>
On Sun, Jan 3, 2010 at 8:34 PM, MacRuby <ruby-noreply@macosforge.org> wrote:
#528: Improve Tail Call Elimination
-------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco
-------------------------------------+--------------------------------------
Comment(by haruki.zaemon@…):
I dug a little deeper and apparently LLVM already supports quite sophisticated TCO, including mutual recursion. Not sure why that doesn't take effect in MacRuby but I assume it's due to the way calls are constructed. Anyway, it's now well and truly outside my abilities.
Thanks, Simon
Simon, after reading you blog post on the subject, I feel that you're well versed on the subject matter of TCO. Yes, LLVM supports TCO very well and building languages in general. I would recommend learning a bit about LLVM and llvm.org has some excellent documentation. Also, they have several resources to receive assistance. After you feel comfortable with LLVM, then looking at the problem within the MacRuby would should become much easier. Good luck, -Conrad
-- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:12> MacRuby <http://macruby.org/>
Simon, I'd like to second the recommendation to not lose heart so quickly here! If LLVM already supports the kind of TCO optimization you're looking for then that's half the battle right there. MacRuby's usage of LLVM is already pretty sophisticated, but no one (least of all Laurent) would claim it's "finished", particularly in terms of all the various optimizations that might conceivably be done (the axiom "first make it work, *then* make it work fast" applies to most of the project's current priorities). I encourage you to keep looking into it, if only as a learning exercise. There are also other projects which use LLVM (http://llvm.org/ProjectsWithLLVM/) that might prove illustrative, if only to provide useful points of comparison. - Jordan On Jan 3, 2010, at 10:20 PM, Conrad Taylor wrote:
Simon, after reading you blog post on the subject, I feel that you're well versed on the subject matter of TCO. Yes, LLVM supports TCO very well and building languages in general. I would recommend learning a bit about LLVM and llvm.org has some excellent documentation. Also, they have several resources to receive assistance. After you feel comfortable with LLVM, then looking at the problem within the MacRuby would should become much easier.
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by lsansonetti@…): We should be able to do much more sophisticated tall call elimination with the new VM changes I'm working on (which allow method inlining). I will investigate that, for 0.6. -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:13> MacRuby <http://macruby.org/>
#528: Improve Tail Call Elimination -------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco -------------------------------------+-------------------------------------- Comment(by haruki.zaemon@…): Replying to [comment:13 lsansonetti@…]:
We should be able to do much more sophisticated tall call elimination with the new VM changes I'm working on (which allow method inlining). I will investigate that, for 0.6.
Sounds great. My C++ is 15 years old so I suspect I'm of no help. Thanks for listening anyway :) -- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:14> MacRuby <http://macruby.org/>
So, can the TCO elimination pass actually perform TCO for mutually recursive methods and the compiler just isn't phrasing method invocations in a compatible way? Also, better method inlining support is awesome, but my intuition tells me that there isn't a lot of overlap between implementing TCO and inlining. Laurent, is there something I can learn from this? :) Best, Jeremy On Mon, Jan 4, 2010 at 2:50 PM, MacRuby <ruby-noreply@macosforge.org> wrote:
#528: Improve Tail Call Elimination
-------------------------------------+-------------------------------------- Reporter: haruki.zaemon@… | Owner: lsansonetti@… Type: enhancement | Status: new Priority: minor | Milestone: Component: MacRuby | Keywords: tail call elimination optimisation tco
-------------------------------------+--------------------------------------
Comment(by haruki.zaemon@…):
Replying to [comment:13 lsansonetti@…]:
We should be able to do much more sophisticated tall call elimination with the new VM changes I'm working on (which allow method inlining). I will investigate that, for 0.6.
Sounds great. My C++ is 15 years old so I suspect I'm of no help. Thanks for listening anyway :)
-- Ticket URL: <http://www.macruby.org/trac/ticket/528#comment:14> MacRuby <http://macruby.org/>
participants (4)
-
Conrad Taylor
-
Jeremy Voorhis
-
Jordan K. Hubbard
-
MacRuby