On Fri, Sep 11, 2015 at 4:13 AM, Steven D'Aprano wrote:
Sometimes they might be. But in general, I think it is meaningless to expect
a imperative command to have a return result. The whole point of an
imperative command is that it operates by side-effect.

For example, what would `del x` return if it were an expression instead of a
statement? I can think of two reasonable alternatives, but both feel a bit
wrong to me.

(1) Return True if x was successfully unbound, False if it wasn't. Except
that raising an exception seems more Pythonic, in which case returning True
seems redundant. It will *always* return True, unless there's an exception.
So why bother? We only bother because there's no way to *not* return a
result if "everything is an expression".

(2) Return None, like functions do by default. But again, it only returns
None, not because None is a meaningful thing to return, but because we
don't actually have a way to say "it doesn't return anything".

Yes, or: (3) Return the old value that x contained, the way dict.pop()
does. That makes it a "destructive retrieval" rather than simply a
destruction operation.

Or os.abort. The docs for that say:

Help on built-in function abort in module posix:

abort() -> does not return!

Abort the interpreter immediately. This 'dumps core' or otherwise fails
in the hardest way possible on the hosting operating system.

So, what would os.abort() return, if everything is an expression?

Since this is in the os module, and is thus a thin wrapper around
lower-level operations, I could imagine it returning an error code
(the way the C-level exec functions do - if they succeed, they don't
return, but if they fail, they return an error number); in Python,
it'd be best to have it either abort the process (and thus not
return), or raise an exception (and thus not return).

But abort functions are a rarity. It's not a problem to have a rule
"all functions must return something" (as Python does), and then have
functions that never actually use the normal return path:

def raise_(exc): raise exc
raise_stopiteration = iter([]).__next__
raise_typeerror = lambda: ""()

Calling one of these functions is *syntactically* an expression, but
at run time, it'll never actually get as far as producing a value. If
it's at all possible for the operation to, based on run-time
information, NOT abort, then it absolutely has to be able to return.

Because that's the definition of an expression in this context. An
expression is evaluated to either return a result, or raise an exception.

I'd define it more simply: An expression always produces a result.
It's possible that, during the evaluation of an expression, an
exception will be raised; if that happens, evaluation stops. Doesn't
matter whether the expression itself caused that, or if an OS-level
signal did (eg triggering KeyboardInterrupt), or if the expression was
"yield 1" and an exception got thrown in. But yes, an expression is
something that generates a result; a statement isn't.


Search Discussions

Discussion Posts


Follow ups

Related Discussions



site design / logo © 2017 Grokbase