[Python-ideas] Inline Function - idea

Steven D'Aprano steve at pearwood.info
Tue Feb 18 23:45:14 CET 2014


On Tue, Feb 18, 2014 at 10:07:20AM -0700, Alex Rodrigues wrote:
> > Alex, can you explain the difference (if any) between your proposal and dynamic scoping?
> >
> > -- Steven
> 
> Inline functions would be a bit like dynamic scoping and a bit like 
> macros. The main difference from dynamic scoping is that they would 
> not search up beyond their parent to find names, 

What is "their parent"? Is that the function they are defined in, or the 
function they are called in?


> since they act 
> exactly like code injected at the spot they are called it is expected 
> that the variables they are using (like the ones in it's parent) are 
> either locals or globals.

But that is *not how it works* if you actually type the code in that 
spot. If you have code that looks like this:

def spam():
    def eggs():
        def cheese():
            ### <= insert code here


then code inserted into cheese *will* search the eggs and spam local 
variables as well as globals. Having "inline code" skip over eggs and 
spam namespaces is a major difference in behaviour.

The advantage of dynamic scoping is that it is a standard, 
well-understood execution model that can easily be described. The pros 
and cons are well known. There are more cons than pros, which is why 
very few modern languages support it.

Your suggestion seems to be half dynamic, half lexical (static), but not 
quite the same as either. So it would be completely innovative, and 
since nobody has used this before, nobody can know how well it will work 
in practice.


> I'm not sure that that has many advantages 
> outside of demanding less from the runtime,

How do you know it demands less from the runtime?


> but that's how I imagined 
> it. IMO The biggest advantage to inline functions over other 
> constructs is ease of understanding. 

Well I don't understand it. Flat scoping, like in Python before 
nested_scopes was introduced, that's easy. Nested scopes (static or 
lexical scoping), that's also easy to understand: scope follows the 
layout of your code when indented. That's extremely intuitive.

Dynamic scoping is a bit harder to grasp, but not very much so. A 
function sees the variables in the code that calls it, not the code 
where it was defined. So if you have a function spam that calls eggs 
that calls cheese, cheese sees the local variables inside eggs and spam.

But yours, well, I'm not quite sure how it's supposed to work, beause it 
is half static and half dynamic and all confusing. I believe that you 
think this is a simple model to understand because you're only thinking 
of simple cases. But what happens if you have an inline function call an 
inline function?

def regular():
    x = 42
    inline()

@make_inline
def inline():
    another_line()

@make_inline
def another_inline():
    print(x)


According to your comment above, another_inline should NOT follow the 
normal dynamic scoping search path:

    - does another_inline have a local variable x?
    - if not, does inline have a local variable x?
    - if not, does regular have a local variable x?  <=== FOUND
    - if not, look for a global

instead it should follow:

    - does another_inline have a local variable x?
    - if not, does inline have a local variable x?
    - do not search regular, since that is too deep
    - skip straight to globals

But that contradicts the idea that the code in another_inline should 
behave just as if it were typed inside inline. So your description is 
ambiguous -- will calling regular() above raise a NameError, or will it 
print 42?

There are *all sorts* of odd corners to be considered. What happens if 
another_inline is declared *inside* inline, rather than outside? What 
happens if another_inline is declared inside *regular*? What if it's a 
closure that has come from somewhere else?

I don't have any intuition to be able to immediately guess what the 
behaviour in these cases will be. I think that either static or dynamic 
scoping is easy to reason about, but your hybrid is not.


> We may you be used to 
> understanding scoping after lots of programming, but it's not always 
> intuitive. On the other hand it is extremely intuitive to understand 
> "when you call this, all that code runs exactly as if you had typed it 
> here".

But that's not what you described earlier. See my earlier comment.


-- 
Steven


More information about the Python-ideas mailing list