[Python-ideas] combining two threads: switch statements and inline functions

Andrew Barnert abarnert at yahoo.com
Wed Feb 12 11:07:36 CET 2014


From: Steven D'Aprano <steve at pearwood.info>

Sent: Tuesday, February 11, 2014 7:29 PM


> On Tue, Feb 11, 2014 at 03:05:53PM -0800, Bruce Leban wrote:
>>  What if we had the ability to write dictionaries with inline functions in
>>  them.
> 
> What's an inline function? I've asked in the inline function thread how 
> it differs from a regular function with dynamic scoping, but haven't had 
> a response yet. Since you're now extending the proposal, perhaps you can 
> answer.
> 
> Is it a function that uses dynamic scoping instead of static scoping? A 
> multi-line anonomous function? Some sort of closure? A thunk?

I think neither Alex Rodrigues's initial idea nor Bruce Leban's side idea area any of these.

First, Bruce Leban isn't really asking for multi-line anonymous functions, but for multi-line functions that are expressions. These are entirely independent things. (Look at JavaScript: "function [name] { <statements> }" is an expression.) Notice that Bruce wrote a second post to specifically clarify that he wants to do non-expression things like assigning to variables. Being able to use statements in an expression is where all the power comes from, and all of the problems, when people talk about "multi-line lambdas", not being able to leave the name off. Bruce was just proposing YA syntax for the usual extended lambdas—but getting some mileage out of restricting them to appearing to a new special kind of display expression.


Meanwhile, Alex was proposing something very different. Really, what he wants is runtime computational (i.e., bytecode) macros. Look at his motivating example:

    @inline
    def element_wise(func):
        func = inline(func) 
        for …:
            func()

    def is_symmetric(matrix):
        element_wise(lambda: if matrix[i][j] != matrix[j][i]: return False)
        return True


Forget about how the variables work for the moment (and the fact that, on top of his main desire, he _also_ wants a statement inside his lambda…) and look at that "return False". Clearly it has to return from not just the lambda, but element_wise, and is_symmetric. That's the key here; that's what makes it "inline" in Alex's terms. It's not a function on the stack with its own frame, it's just code that gets compiled as a function, but then executed inline directly in the calling function's frame. This doesn't quite work for a few relatively minor reasons (functions get an implicit "return None", variables are referred to by index and may not have the right indices, etc.), but the idea isn't nonsense.

Once you see that, dynamic vs. lexical scope is a red herring. Either way, the stack frame in which matrix gets evaluated is the stack frame of is_symmetric. The existing closure variable lookup does the right thing. (Note that the definition of the lambda forces matrix to be looked up via *_DEREF in is_symmetric, so the *_DEREF code in the lambda is correct when inlined.) And it would _have_ to be right for the return-through to make any sense. Dynamic scope doesn't seem to add any possibilities here that it wouldn't already add in regular functions; I think it's orthogonal, and irrelevant, to the proposal. But I could be wrong.

Anyway, I don't think he really needs runtime macros; he only needs "func = inline(func)" because element_wise itself is defined as a function and converted to a macro with "@inline". If the latter were compile-time, the former could be as well. (Imagine a "defmacro" statement and a "lambdamacro" expression.) And that eliminates a whole lot of complexity (dynamically generating dynamic code-fixup code, etc.). And if you don't need runtime macros, you probably don't need computational macros, which eliminates even more (e.g., in the AST, "matrix" is a name, not an index). The key thing he wants is macros. But what he asked for is runtime computational macros.


More information about the Python-ideas mailing list