
On Wednesday, January 20, 2016 10:59 AM, Terry Reedy <tjreedy@udel.edu> wrote:
Use ';' in the parameter list, followed by name=expr pairs.
This is the best option anyone's suggested (short of just not doing anything and telling people to keep using the default-value trick on the rare occasions where this is necessary). However, I'd suggest one minor change: for the common case of `j=j, len=len`, allow people to just write the name once. The compiler can definitely handle this: def spam(eggs; _i=i, j, len):
The
question is whether names after are initialized local variables, subject to rebinding at runtime, or named constants, with the names replaced by the values at definition time.
They almost certainly should be variables, just like parameters, with the values stored in `__defaults__`. Otherwise, this code: powers = [lambda x; i: x**i for i in range(5)] ... produces functions with their own separate code objects, instead of functions that share a single code object. And this isn't some weird use case; the "defining functions in a loop that capture the loop iterator by value" is the paradigm case for this new feature. (It's even covered in the official FAQ.) The performance cost of those separate code objects (and the cache misses caused when you try to use them in a loop) has almost no compensating performance gain (`LOAD_CONST` isn't faster than `LOAD_FAST`, and the initial copy from `__defaults__` at call time is about 1/10th the cost of either). And it's more complicated to implement (especially from where we are today), and less flexible for reflective code that munges functions.
In the former case, a type hint could by
included. In the latter case, which is much better for optimization, the fixed object would already be typed.
def f(int a, int b=1; int c=2) => int
You've got the syntax wrong. But, more importantly, besides the latter case (const vs. default) actually being worse for optimization, it isn't any better for type inference. In this function: def f(a: int, b: int=1; c=2) -> int: or even this one: def f(): for i in range(5): def local(x: int; i) -> int: return x**i yield local ... the type checker can infer the type of `i`: it's initialized with an int literal (first version) or the value of a variable that's been inferred as an int; therefore, it's an int. So it can emit a warning if you assign anything but another int to it. The only problem with your solution is that we now have three different variations that are all spelled very differently: def spam(i; j): # captured by value def spam(i): nonlocal j # captured by variable def spam(i): # captured by variable if no assignment, else shadowed by a local Is that acceptable?