
On Tue, Jan 19, 2016 at 05:01:42PM -0800, Guido van Rossum wrote:
On Tue, Jan 19, 2016 at 4:37 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, Jan 19, 2016 at 08:47:28AM -0800, Guido van Rossum wrote:
I think it's reasonable to divert this discussion to "value capture". [...] If I understand you correctly, that's precisely what a function default argument does: capture the current value of the default value expression at the time the function is called.
I think you misspoke here (I don't think you actually believe what you said :-).
Function defaults capture the current value at the time the function is *define*.
Oops! You got me. Yes, I meant defined, not called. [...]
The best syntax for such capture remains to be seen. ("Capture" seems to universally make people think of "variable capture" which is the opposite of what we want here.)
If I recall correctly, there was a recent(?) proposal for a "static" keyword with similar semantics:
def func(a): static b = expression ...
would guarantee that expression was evaluated exactly once.
Once per what? In the lifetime of the universe? Per CPython process start? Per call?
J/K, I think I know what you meant -- once per function definition (same as default values).
That's what I mean. Although, I am curious as to how we might implement the once per lifetime of the universe requirement :-)
If that evaluation occurred when func was defined, rather than when it was first called,
(FWIW, "when it was first called" would be a recipe for disaster and irreproducible results.)
It probably would be a bug magnet. Good thing I'm not asking for that behaviour then :-) [...]
Scoping rules might be tricky to get right. Perhaps rather than a declaration, "static" might be better treated as a block:
Why? This does smell like a directive similar to global and nonlocal.
I'm just tossing the "static block" idea out for discussion, but if you want a justification here are two differences between capture/static and global/nonlocal which suggest they aren't that similar and so we shouldn't feel obliged to use the same syntax. (1) global and nonlocal operate on *names*, not values. E.g. after "global x", x refers to a name in the global scope, not the local scope. But "capture"/"static" doesn't affect the name, or the scope that x belongs to. x is still a local, it just gets pre-initialised to the value of x in the enclosing scope. That makes it more of a binding operation or assignment than a declaration. (2) If we limit this to only capturing the same name, then we can only write (say) "static x", and that does look like a declaration. But maybe we want to allow the local name to differ from the global name: static x = y or even arbitrary expressions on the right: static x = x + 1 Now that starts to look more like it should be in a block of code, especially if you have a lot of them: static x = x + 1 static len = len static data = open("data.txt").read() versus: static: x = x + 1 len = len data = open("data.txt").read() I acknowledge that this goes beyond what the OP asked for, and I think that YAGNI is a reasonable response to the static block idea. I'm not going to champion it any further unless there's a bunch of interest from others. (I'm saving my energy for Eiffel-like require/ensure blocks *wink*). -- Steve