[top posting from my phone]

Chris Angelico points out the & part of the idea interacts poorly with *args 
and **kwargs, so I drop that idea. 

Re-reading PEP 312, this idea is basically identical, with different spellings. 

The point remains: do we want  to be able to create unevaluated expressions 
that can be evaluated at a different point?

--
Eric.

> On Nov 6, 2016, at 8:06 AM, Eric V. Smith <e...@trueblade.com> wrote:
> 
> Creating a new thread, instead of hijacking the PEP 532 discussion.
> 
> From PEP 532:
> 
> > Abstract
> > ========
> >
> > Inspired by PEP 335, PEP 505, PEP 531, and the related discussions, this PEP
> > proposes the addition of a new protocol-driven circuit breaking operator to
> > Python that allows the left operand to decide whether or not the expression
> > should short circuit and return a result immediately, or else continue
> > on with evaluation of the right operand::
> >
> >     exists(foo) else bar
> >     missing(foo) else foo.bar()
> 
> Instead of new syntax that only works in this one specific case, I'd prefer a 
> more general solution. I accept being "more general" probably seals the deal 
> in killing any proposal!
> 
> I realize the following proposal has at least been hinted at before, but I 
> couldn't find a specific discussion about it. Since it applies to the 
> short-circuiting issues addressed by PEP 532 and its predecessors, I thought 
> I'd bring it up here. It could also be used to solve some of the problems 
> addressed by the rejected PEP 463 (Exception-catching expressions). See also 
> PEP 312 (Simple Implicit Lambda). It might also be usable for some of the use 
> cases presented in PEP 501 (General purpose string interpolation, aka 
> i-strings).
> 
> I'd rather see the ability to have unevaluated expressions, that can later be 
> evaluated. I'll use backticks here to mean: "parse, but do not execute the 
> enclosed code". This produces an object that can later be evaluated with a 
> new builtin I'll call "evaluate_now". Obviously these are strawmen, and 
> partly chosen to be ugly and unacceptable names and symbols in the form I'll 
> discuss here.
> 
> Then you could write a function:
> 
> eval_else(`foo.bar`, `some_func()`)
> 
> whose value is foo.bar, unless foo.bar cannot be evaluated, in which case the 
> value is some_func().
> 
> def eval_else(expr, fallback, exlist=(AttributeError,)):
>    try:
>        return evaluate_now(expr)
>    except exlist:
>        return evaluate_now(fallback)
> 
> Exactly which exceptions you catch is up to you. Of course there's the chance 
> that someone would pass in something for which the caught exception is too 
> broad, and it's raised deep inside evaluating the first expression, but 
> that's no different than catching exceptions now. Except I grant that hiding 
> the try/except inside a called function increases the risk.
> 
> Like f-strings, the expressions are entirely created at the site they're 
> specified inside ``. So they'd have access to locals and globals, etc., at 
> the definition site.
> 
> def x(foo, i):
>    return eval_else(`foo.bar`, `some_func(i, __name__)`)
> 
> And like the expressions in f-strings, they have to be valid expressions. But 
> unlike f-strings, they aren't evaluated right when they're encountered. The 
> fact that they may never be evaluated is one of their features.
> 
> For example the if/else expression:
> 
> if_else(`y`, x is None, `x.a`)
> 
> could be defined as being exactly like:
> 
> y if x is None else x.a
> 
> including only evaluating x.a if x is not None.
> 
> def if_else(a, test, b):
>    if test:
>        return evaluate_now(a)
>    return evaluate_now(b)
> 
> You could do fancier things that require more than 2 expressions.
> 
> Whether `` returns an AST that could later be manipulated, or it's something 
> else that's opaque is another discussion. Let's assume it's opaque for now.
> 
> You could go further and say that any argument to a function that's specially 
> marked would get an unevaluated expression. Suppose that you can mark 
> arguments as & to mean "takes an unevaluated expression". Then you could 
> write:
> 
> def if_else(&a, test, &b):
>    if test:
>        return evaluate_now(a)
>    return evaluate_now(b)
> 
> And call it as:
> if_else(y, x is None, x.a)
> 
> But now you've made it non-obvious at the caller site exactly what's 
> happening. There are other downsides, such as only being able to create an 
> unevaluated expression when calling a function. Or maybe that's a good thing!
> 
> In any event, having unevaluated expressions would open up more possibilities 
> than just the short-circuit evaluation model. And it doesn't involve a new 
> protocol.
> 
> Eric.
> _______________________________________________
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
> 

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to