[Python-ideas] combining two threads: switch statements and inline functions
Steven D'Aprano
steve at pearwood.info
Wed Feb 12 04:29:19 CET 2014
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? Some of
the above? In the previous discussion, it appears to be a regular
function using dynamic scoping. Here it appears to be more kind of like
a thunk, in that it makes up an expression.
https://en.wikipedia.org/wiki/Thunk_%28functional_programming%29
Looking at your example here:
> def sample(i, op, j):
> switcher = {{
> '-':: if i > j:
> return i - j
> else:
> return j - i;;
> '+':: return i + j;;
> }}
> return switcher[op]()
I think it is silly to limit these "inline functions" to only be placed
inside dictionaries. What if you want one stand-alone? Or in a list?
Inserting them inside a dictionary should be merely a special case of
the more general case, a multi-line "inline function" that is
syntactically an expression. (Like lambda, only super-powered.)
So let's toss out the mutated dict syntax, and use a normal dict,
assuming only some special syntax for something to delay computation
until called later. I'm going to call it "thunk" rather than inline
function, since to me that appears to be the closest match, and use the
simplest syntax that might work. Consider this pseudo-code rather than
my proposal for actual "thunk" syntax.
switcher = {
# Receives i, j and op from the scope of the caller.
'-': thunk if i > j:
return i - j
else:
return j - i,
'+': thunk return i + j,
None: thunk raise OperatorError("unknown operator %s" % op),
}
You then use these thunks something like this:
def sample(i, op, j):
return switcher.get(op)()
It doesn't really buy you much benefit over normal functions with static
(lexical) scoping:
def sample(i, op, j):
return switcher.get(op)(i, op, j)
If there is a benefit to dynamic scoping, surely it needs to be more
than saving a couple of explicit arguments? I would argue that the
benefit of being able to explicitly read the arguments there in the
function call far outweighs the cost of having to explicitly write the
arguments.
Remember that dynamic scoping is rare in programming languages, because
it is normally considered a poor idea. It's not hard to implement, but
it is hard to use right. Personally, I'm very excited by the idea of
dynamic scoping, but in my opinion it's in desperate need of a good
use-case.
So what have we got here?
- The idea of dynamic scoping doesn't seem to gain us much, perhaps a
little less typing, but only at the cost of making calls less explicit
and hence harder to understand. (In other words, I'm still looking for
a good use-case. This isn't it.)
- We're no closer to finding good syntax for a multi-line anonymous
function which can be used in expressions, regardless of what scoping
rules the function uses. My "thunk" syntax above doesn't really work
for me, it's just the first and most explicit syntax I thought of.
- But if we somehow solve the second problem, regardless of how the
functions are scoped, then we can trivially use it inside function
calls, dicts, sets, lists, attribute assignments, ...
In other words:
* scoping and multi-line functions are orthogonal;
* dicts are a red herring;
* we're no closer to a multi-line lambda than we were 20 years ago.
--
Steven
More information about the Python-ideas
mailing list