Skip to content
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

Inline/Optimization Macros - Take 2 #60

Open
Varriount opened this issue Sep 7, 2013 · 3 comments
Open

Inline/Optimization Macros - Take 2 #60

Varriount opened this issue Sep 7, 2013 · 3 comments

Comments

@Varriount
Copy link

So after reading the reasons why my first proposal of a single Optimization Macro parsing the entire file was unfeasible, I got to thinking of better (and possibly more pythonic) ways of implementing inlined function calls.

Instead of a single macro, inlining a function would require two macros - one to register a target function as inline-able, and another to actually inline the registered function into a call site.
Proposed usage:

@inlineable
def foo(x, y):
    return x+y


def bar():
    for number in range(0,1000):
        inline(result = foo(number, number+1))
        print(result)

Or

@inline_all
def bar():
    for number in range(0,1000):
        result = foo(number, number+1)
        print(result)

Alternatives to using the the "inline" macro as a function is to use it as a decorator, and have it attempt to scan and inline every registered function call within the body.

I believe that, with some usage limitations, this kind of optimization is quite possible. The only difficulties lie in restructuring function bodies so that they can be safely inlined. Argument handling is also a bit tricky, but I believe that clever use of python's symtable module, along with comparison of the function's argument ast should solve that.

@lihaoyi
Copy link
Owner

lihaoyi commented Sep 8, 2013

Seems perfectly doable; With the recently developed (but still undocumented) @Scoped walker, I do not think that hygienically renaming the variables within function bodies before inlining will prove difficult.

Possible caveat: you're probably going to need separate cases for inlined expressions and inlined statements, due to the fact that in python you cannot place statements inside expressions. That would cause problems inlining e.g. a multi-statement function as an expression.

Other than that, go ahead, look forward to see what you come up with =)

@lihaoyi
Copy link
Owner

lihaoyi commented Sep 8, 2013

One possible approach for single-expression-functions would be to make the @inlineable decorator a macro, that will capture the contents of the function and replace it with a macro function which registers itself and performs the inlining. i.e.

@inline
def func(a, b):
    return a * a + b * b # only works for single expression functions

expands into

@macro.expr
def func(tree, all_trees):
    return q[(lambda a, b: a * a + b * b)(ast[all_trees[0]], ast[all_trees[1]])]

which is then used via

print func[1 + 1, 2 + 2] # 9

This can be done pretty straightforwardly, and will "inline" the functions body, but I'm not sure if it will actually make anything any faster. We still need the lambda expression in order to perform variable binding, since we can't inline local variable assignments in expressions otherwise, and that probably will undo the performance benefit from inlining in the first place.

@gordianknotC
Copy link

How about this

# mark do_something and do_anotherthing as template and store it's code body.
with template:
    def do_something(x,y):
        print "do something...."

    def do_anotherthing(x,y): pass

# to use do_something as inline function just decorating inlineable ontop templateTester
@inlineable
def templateTester():
    do_something(1,2)

#to use do_something as normal function
def normalFunctionTester():
    do_something(1,2)

Why called template? Because I first learned this concept from Nimrod template

Another interesting and doable things to implement is "do notation"(borrowed from Nimrod do notation)

instead of writing

def walkWhile(condition, do):
    if condition: do(x,y)

def do_func(x,y):
    do something here.....

walkWhile(condition, do_func)

do notation would be more convenient

def walkWhile(condition, do):
    if condition: do(x,y)

walkWhile(condition) do(x,y):
    do something here.....

But due to semantic limitation we can't use
walkWhile(condition) do:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants