On Sat, Sep 19, 2015 at 03:17:07AM -0500, C Anthony Risinger wrote:
I really liked this whole thread, and I largely still do -- I?think -- but I'm not sure I like how `?` suddenly prevents whole blocks of code from being evaluated. Anything within the (...) or [...] is now skipped (IIUC) just because a `?` was added, which seems like it could have side effects on the surrounding state, especially since I expect people will use it for squashing/silencing or as a convenient trick after the fact, possibly in code they did not originally write.
I don't think this is any different from other short-circuiting operators, particularly `and` and the ternary `if` operator: result = obj and obj.method(expression) result = obj.method(expression) if obj else default In both cases, `expression` is not evaluated if obj is falsey. That's the whole point.
If the original example included a `?` like so:
response = json.dumps?({ 'created': created?.isoformat(), 'updated': updated?.isoformat(), ... })
should "dumps" be None, the additional `?` (although though you can barely see it) prevents *everything else* from executing.
We're still discussing the syntax and semantics of this, so I could be wrong, but my understanding of this is that the *first* question mark prevents the expressions in the parens from being executed: json.dumps?( ... ) evaluates as None if json.dumps is None, otherwise it evaluates the arguments and calls the dumps object. In other words, rather like this: _temp = json.dumps # temporary value if _temp is None: response = None else: response = _temp({ 'created': None if created is None else created.isoformat(), 'updated': None if updated is None else updated.isoformat(), ... }) del _temp except the _temp name isn't actually used. The whole point is to avoid evaluating an expression (attribute looking, index/key lookup, function call) which will fail if the object is None, and if you're not going to call the function, why evaluate the arguments to the function?
This may cause confusion about what is being executed, and when, especially once nesting (to any degree really) and/or chaining comes into play!
Well, yes, people can abuse most any syntax.
Usually when I want to use this pattern, I find I just need to write things out more. The concept itself vaguely reminds me of PHP's use of `@` for squashing errors.
I had to look up PHP's @ and I must say I'm rather horrified. According to the docs, all it does is suppress the error reporting, it does nothing to prevent or recover from errors. There's not really an equivalent in Python, but I suppose this is the closest: # similar to PHP's $result = @(expression); try: result = expression except: result = None This is nothing like this proposal. It doesn't suppress arbitrary errors. It's more like a conditional: # result = obj?(expression) if obj is None: result = None else: result = obj(expression) If `expression` raises an exception, it will still be raised, but only if it is actually evaluated, just like anything else protected by an if...else or short-circuit operator. -- Steve