
On 10/01/2015 04:12 PM, Random832 wrote:
On Thu, Oct 1, 2015, at 16:57, Ron Adam wrote:
And to go out on a limb...;-)
Another possibility is to have a*special magic callable* that when called skips the argument evaluation and returns None.
That's dangerous talk indeed. Special magic callables are Lisp territory.;)
It's also lambda calculus territory.
And I don't even know how you'd implement it efficiently without them being known at compile-time.
I guess at*every* callsite you could test if the callable is magic, and if it is evaluate the arguments, and if it's not just pass in a lambda that will return the arguments. But you've got to generate those lambdas for*all* callsites, even the vast majority that will never be a magic callable.
I realized this evening the parser doesn't need to know at parse time, and the object doesn't need to be special. It's the syntax that gives it the specialness, not the object. So what I was thinking is still possible, but it would work more like the other suggestions. If you look at byte code generated for a function call...
def bar(x, y): ... return x + y ... def foo(x, y): ... return bar(x+1, y+1) ... dis(foo) 2 0 LOAD_GLOBAL 0 (bar) 3 LOAD_FAST 0 (x) 6 LOAD_CONST 1 (1) 9 BINARY_ADD 10 LOAD_FAST 1 (y) 13 LOAD_CONST 1 (1) 16 BINARY_ADD 17 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 20 RETURN_VALUE
You will notice the function is loaded on the stack *before* the argument expressions are evaluated. It won't require generating lamba expressions, just a conditional jump where '?(' is used. So no, it won't be required at every call site. Something roughly like ... (presume the index's are adjusted correctly) 2 0 LOAD_GLOBAL 0 (bar) #-- inserted only if '?(' is used -------------- POP_JUMP_IF_NOT_NOCALL 3 LOAD_CONST 0 (None) JUMP_FORWARD 8 (to 20) #----------------------------------------------- 3 LOAD_FAST 0 (x) 6 LOAD_CONST 1 (1) 9 BINARY_ADD 10 LOAD_FAST 1 (y) 13 LOAD_CONST 1 (1) 16 BINARY_ADD 17 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 20 RETURN_VALUE So the parser doesn't need to know if it's the NoneCall object at parse time, it just needs to know to check for it, and the ?( syntax can tell it to do that only where it's needed. There really isn't anything special about the NoneCall object, it's just a reserved builtin object. And adding the check for it isn't all the special either. It's the behavior that is special because of the ?( sytnax. I was thinking it could call a __cond_call__ method on the object. That extra indirect call could allow objects to specify how they respond to ?( conditional calls. It's just requires an extra LOAD_ATTR and call it with no arguments in the bytecode. The case of unpacking the args if the object is None would require an additional check for None and to load an identity function in it's place or could be done by adding a __cond_call__ method (if that is how ?( will work) to None that is an identity function. value = obj?(default) #None?(default) --> identity(default) Think of these as moving conditions that would otherwise be elsewhere to a more convenient location. So I don't expect them to be much slower than the equivalent code that does the same thing. A __cond_call__ method works because it can't conflict with __call__. So it avoids any conflicts that might occur by calling __call__ by mistake. The point is that a conditional call syntax could also fill the need of the or None operator. The specific details may be a bit different than what I describe here, but I think it's doable.
What if the callable only wants*some* of the arguments? Hey, if this had existed back then the ternary operator could have been a normal function - instead of (b() if a else c()) just do iif(a, b(), c()).
Only wanting some arguments would be much harder. It might be done by splitting the arguments into nested ?( calls similar to how we apply multiple decorators. I don't expect it to be pretty or practical, so lets just not go there for now.
And is this going to be fully general? I.e. should this be supported for regular operators? If __add__ is magic does + do this, for example?
No, it would only work with ?( syntax. Cheers, Ron