[Python-3000] Switch and static, redux
Greg Ewing
greg.ewing at canterbury.ac.nz
Mon Jul 10 01:45:03 CEST 2006
Guido van Rossum wrote:
> On 7/7/06, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
>
>> You seem to be conflating "nested functions" and
>> "functional programming", which doesn't make sense
>> to me.
>
> Not even a smidgen? Small nested functions (or lambdas) are pretty
> common in a functional style.
Yes, but the implication doesn't go the other way --
there are uses for nested functions outside of the
functional paradigm.
The defining characteristic of the functional style
is absence of side effects, not presence of nested
functions. And it's certainly not absence of case
statements -- case-like pattern matching is used
all the time in functional languages.
> I don't like storing it as a global; and that's probably incorrect
> too, e.g. if multiple definitions of f are being made in a loop.
I'm not so sure it would be wrong -- the cases are
meant to be constant, remember? So they shouldn't
be changing between definitions of f()!
But if you really want to allow for this, it's still
easy -- store in a cell in the f_closure of the function
object created by def f(). Functions nested within f find
it the same way they find any other cell, i.e. it gets
passed down to them through the scoping system. This is
exactly the same mechanism you would use to attach it to
g(), except that you're hauling it up more than one level.
> The kind of optimization that's within reach for the CPython compiler
> is pretty much limited to compile-time constant expressions,
By "optimisation" I just mean avoiding the recomputation of
case values as much as reasonably practical. And it seems
quite reasonably practical to me to only compute the case
values of g() once in the example I gave -- for reasons
which I think are obvious to a human reader of the program.
> Questions like "why did my code suddenly change from O(log N) to O(N)
> performance" are really hard to answer if it's the compiler (not)
> taking a shortcut in one case.
The number of times the cases are evaluated would only
make a constant-factor difference to the running time,
not an O() difference.
> we can have two nearly identical cases involving an outer and an
> inner def, the latter containing a switch; yet one is fast and the
> other is slow, and the clue is that the slow one uses a local variable
> of the outer def in the switch.
That's true, but we seem to differ on how much of a
problem that will be in practice. If the case values
really are constant (we do agree that they *should* be,
don't we?) then this situation is almost never going
to arise, because there's no reason you would want to
use anything other than a module-level variable in a
case. So I'm calling FUD on that one.
With your scheme, the nested case would *always* be
slow, with no straightforward means available to
make it fast. With mine, it would *almost always*
be fast, unless you're trying to do something
screwy like use non-constant cases, in which case
you're asking for trouble anyway.
And if you *mistakenly* use something non-constant as
a case, then that's a bug which is likely to bite
you in other ways as well, so you've got a debugging
problem anyway.
> The other POV is that of the expert
> user trying to understand (accidentally) obfuscated code. I still like
> there to be simple rules to rememver for the latter.
For an expert user, I don't think "outermost possible
function object" is substantially harder to grasp than
"immediately enclosing function object".
--
Greg
More information about the Python-3000
mailing list