-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic tail recursion #3020
Generic tail recursion #3020
Conversation
This allows to evaluate just the first step of the expression, and return the remainder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great. Thanks for splitting up the patch, that helped a lot. I did some additional testing and that looks good too. @kintel can you have an additional look at the context handing. I don't see any issues but I'm still not 100% sure I know about all the details 😄.
LGTM! |
Is it actually because the original code creates a shared pointer in every
if test but the new code only creates the pointer in the one case that
matches?
…On Fri, 6 Sep 2019 at 21:26, Marius Kintel ***@***.***> wrote:
Merged #3020 <#3020> into master.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#3020?email_source=notifications&email_token=AAEKHBN47BXXE42O4XPL5GDQIK4JFA5CNFSM4IHW7FLKYY3PNVWWK3TUL52HS4DFWZEXG43VMVCXMZLOORHG65DJMZUWGYLUNFXW5KTDN5WW2ZLOORPWSZGOTPSZW3Q#event-2615516014>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAEKHBPQLUSWGGHV3LYPDBDQIK4JFANCNFSM4IHW7FLA>
.
|
Yeah, I guess dynamic_pointer_cast would need to mess with the ref count as well : / |
Thanks for merging this! The typeid+static cast being faster, is a combination of two things: the (cheap) typeid check prevents doing more than one cast per loop, and dynamic_cast is slightly slower than static_cast. I'd say it's mostly the typeid thing that matters here. Was thinking too about how to add a performance test, since results depend on the HW used. Probably it will just be a matter of "compare PR performance against master" or something. |
I recently watched a talk discussing that topic... https://www.youtube.com/watch?v=nOwUzFYt0NQ&feature=youtu.be&t=188 (in context of adding pattern matching to C++) |
This re-implements tail recursion of functions; now any self-call in tail position gets to enjoy tail recursion, instead of functions that follow a very specific structure. In particular, let/assert/echo and nested ternary operators can be used freely now.
Unlike at parse time as before, now the decision to use tail recursion is made at run-time, and for each function call instead of each function declaration.
Tried to separate it in a few commits. Here's a summary of changes:
evaluateStep
fromevaluate
. It returns the following Expression, instead of evaluating it.A word on performance; I benchmarked using this silly example:
function speed(n=1000000) = n == 0 ? 42 : speed(n-1);
Initial results weren't too good; it was almost twice as slow as master. So, had to hunt down a few optimizations:
FunctionCall::prepareTailCallContext
Now the speed is more or less the same as on master.