[Python-Dev] Switch statement

Jim Jewett jimjjewett at gmail.com
Fri Jun 23 22:40:12 CEST 2006


In http://mail.python.org/pipermail/python-dev/2006-June/066409.html,
Guido wrote

> (1) An expression of the form 'static' <atom> has the semantics of
> evaluating the atom at the same time as the nearest surrounding
> function definition.

(A)  I prefer a term other than 'static'.

Looking at various contexts in just C, C++, and Java, I have seen
static used to imply (at least) each of private, global, singleton,
class-level, and constant.

This suggested usage sounds more like a cross between "auxiliary
variable in a Lisp lambda form" and "compile-time defined constant".

(B)  I would prefer semantics closer to Java's final variables:  by
declaring something final, you would be promising that the next
expression can be treated as though it were a literal constant.
Python will evaluate it at least once after the "final" keyword but
before it gets used; anything more than that should be up to the
implementation.

The only advantage I see of specifying the time more tightly is that
people could use things that really aren't constant, iff they get the
timing right.

In http://mail.python.org/pipermail/python-dev/2006-June/066432.html,
Steven Bethard posted a fix for the "I-didn't-want-a-closure" problem
that uses this -- but realistically, people would still be burned by
unexpected closures just as often as they are today; the only benefit
is that the correct workaround is cleaner.

First time use has more compelling use cases, but I'm not sure they're
compelling enough.

(C)  Yes, I realize that you prefer to freeze only objects (the
results of expressions), and weren't sure about the form which also
froze the name.  But realistically, if a "final" name is rebound, that
is probably an error worth flagging.  I do realize that this gets into
a wider issue about how to seal a namespace.

> If there is no surrounding function definition,
> 'static' is a no-op and the expression is evaluated every time.

uhm ... OK ... so why even allow it at all?  Just for consistency with
the implied static of a case statement, even though it won't mean the
same thing?

> [Alternative 1: this is an error]

OK, but ...

Things like re.DOTALL should also be final; things like
urlparse.uses_relative should not.  It seems a shame to spend a
keyword saying "treat this as constant" and still not be able to do so
with module-level globals.

> [Alternative 2: it is evaluated before the module is entered;
> this would imply it can not involve any imported names but it can
> involve builtins]

And parsing must take at least one more pass, and static still better
not appear inside an if statement, and ...

> [Alternative 3: precomputed the first time the switch is entered]

OK, though it will be anti-efficient compared to bailing out when you
hit a match.

Alternative 4:  computed at some point after discovering it is final,
but before using it.  For case expressions, this would be after
starting to compute the switch dictionary, but before executing
anything in the suite of this or a later alternative.

> (2) All case expressions in a switch have an implied 'static'.

Good.  But again, I would prefer that the names also be frozen, so
that people won't expect that they can change the clauses; using a
variable in a clause should be fine, but rebinding that name later
(within the same persistent scope) is at best misleading.

> (3) A switch is implemented using a dict which is precomputed at the
> same time its static expressions are precomputed. The switch
> expression must be hashable. Overlap between different cases will
> raise an exception at precomputation time.

Again, I'm not sure it makes sense to specify the time.  Any
specification will cause the following to be well-defined, but someone
will be surprised at any particular result.  My best guess is that it
your proposal would catch ("A1", "B1", "C1", "D2")

    a="A1"
    b="B1"
    c="C1"
    d="D1"
    def f(v):
        if sys.version_info > (2, 5, 0, "", 0):
            a="A2"
        else:
            a="A3"
        b = static "B2"
        c = "C2"
        static d = "D2"
        switch v:
        case in (a, b, c, d): ...

I'm not convinced that we should forbid building the dictionary as
needed, so that it may not contain the last several cases until it
gets an input that doesn't match earlier cases.  (Though I do see the
argument for raising an Exception as early as possible if there are
conflicts.)

-jJ


More information about the Python-Dev mailing list