PEP-308 a "simplicity-first" alternative

Bengt Richter bokr at oz.net
Fri Feb 14 01:28:15 EST 2003


On Thu, 13 Feb 2003 04:44:43 -0700, Steven Taschuk <staschuk at telusplanet.net> wrote:

>Quoth Erik Max Francis:
>  [on Bengt Richter's {x} proposal]
>> So can you rigorously define the behavior of an expression with {}
>> markers in the general case?  Can you even rigorously define it here? 
>> What happens when it appears somewhere other than one of the operands to
>> a logical operator, what then?  Can you even fully define its semantics?
>
>As I read Richter's proposal, {expr} would be an object such as
No, this leads down another path with different semantics.
>	class braced:
>		def __nonzero__(self):
>			return 1
>		def __getattr__(self, name):
>			return (lambda: expr)().__getattr__(name)
>		def __setattr__(self, name, value):
>			return (lambda: expr)().__setattr__(name, value)
>That is, an object which delegates to the value of expr for
>everything except __nonzero__.  (One outstanding question in this
>interpretation is whether, e.g., {expr}.__class__ should refer to
>expr's class or the braced object's.)
>
>Note that expr above is not a variable named 'expr', but a
>metasyntactic variable for an arbitrary expression.  The lambdas
>thus accomplish lazy evaluation, whence the desired short-
>circuiting behaviour in the context "x and {y} or z".  As written
>above they also allow {expr} to change value:
>	>>> x = 3
>	>>> y = {x+1}
>	>>> print y
>	4
>	>>> x += 1
>	>>> print y
>	5
>Memoizing the result of (lambda: expr)() would avoid this, but
>we'd still get:
>	>>> x = 3
>	>>> y = {x+1}
>	>>> x += 1
>	>>> print y
>	5
>(Since, by design, expr would not be evaluated until the first
>invocation of a method other than __nonzero__.)
>
>If memory serves, Richter mentioned that 'or' would "unwrap" the
>braced object, presumably to prevent it from being passed around
>the program and wreaking havoc.  But if used in contexts other
>than the and/or ternary conditional idiom, braced values introduce
>fragility into all sorts of code:
You are describing "braced" according to your interpretation, not my semantics.

>	x = []
>	y = { map(somefunction, x) }
The fact that you are binding y here means that you must bind to the _value_
wrapped inside the {}, and you get that by evaluating the expression. Thus the
above just has the same effect as

 	y =   map(somefunction, x)

>	# ... 50 lines of code fiddling with x, occasionally
>	#     looking at y to find out what x's data maps to
>	#     under somefunction ...
>	if y:              # intended to mean "if y is nonempty"
The intention is fine. The {} was peeled off above, when evaluated for binding to y.
>		print y[0] # possible IndexError
No error -- it should work just as intended.

>(This example is not entirely silly: it could be rewritten with "y
>= lambda: map(somefunction, x)", and "y()" instead of "y"
No, there is no deferral of evaluation of the {x} term once the term
is reached to be evaluated for its normal value. This happens when it
is used in a logical context as well as non-logical. The difference is
that logical true is substituted for whatever the logical value would
have been. The non-logical value is then immediately the value that continues
as such, just as for an unwrapped value.

>thereafter, but the coder might prefer these newfangled braces for
>their terseness.)
>
>Many of these complexities can be avoided by permitting these
>braces only in unwrapping contexts.  In this scenario, they're
Any context that takes the value unwraps it. It's just that in
a logical context, the logical value is True. Note that in a logical
context this two-step access of logical value and normal/unwrapped value
already occurs. E.g., "[] and x" results in [], not 0.

>much more like an inflection of those contexts than a way of
>creating an object with a weird truth value (since the putative
>object would only ever be accessible to the unwrapping context). 
Every non-boolean object is "an object with a weird truth value"
and has to be treated correctly according to context ;-)

>Then the fact that the braces look like some kind of operation on
>or container for the enclosed expression is misleading, and a
>separate, more perspicuous, syntax for those contexts would be
>preferable.
This can be a workable way to look at it.

>
>That leaves us back where we started, seeking a clear syntax for
>the ternary conditional.
Yup ;-)

Regards,
Bengt Richter




More information about the Python-list mailing list