Statements as expressions [was Re: Undefined behaviour in C]

Steven D'Aprano steve at pearwood.info
Tue Mar 29 20:05:51 EDT 2016


On Tue, 29 Mar 2016 10:31 pm, BartC wrote:

> On 29/03/2016 09:26, Steven D'Aprano wrote:
>> On Monday 28 March 2016 12:40, Paul Rubin wrote:
> 
> 
>> The point is that there's nothing intrinsically obvious or right about
>> "return the value of the last statement in the block".
> 
> But that's exactly what happens inside a typical function: you have
> linear sequence of statements, then you a have return statement: at the
> end. It's a common pattern.

But return is an *explicit* exit. And not all languages work that way.


{My Pascal syntax may be a bit rusty...}
function demo(int x): int;
begin
  demo := x + 1;  {sets the return value}
  writeln('x has the value', x);
  writeln('returning now...');
end;


[...]
>> An expression naturally and intrinsically should return the value the
>> expression calculates. This is such a no-brainer that I feel stupid even
>> writing it: "x+1" should return "x+1". It would be crazy to pick
>> something else.
> 
> (This is in contradiction to what you say elsewhere, where:
> 
>    graph + node
> 
> may be procedural.)

Not at all. With operator overloading, the plus operator + ends up as a
method call __add__ or __radd__. This method call can have side-effects,
and it can return anything it likes, including None. That return value can
be ignored, but it is still the return value of the expression:

graph + node  # returns None, use this expression for the side-effects only


Just like print(a, b, c) returns None, and we use if for the side-effects.
It's still an expression ("call the print function with these arguments"),
it does something (prints) and then returns None.


>> But a statement is a statement because it doesn't have a return value.
> 
> Isn't an expression technically a statement in Python? 

I mean statements which are not legal expressions, like:

del x
import module
from module import name
for x in seq: block
while condition: block
try ... except ... else ... finally

etc. I'm sorry that I wasn't pedantic enough to specify "statements (apart
from expressions)" each time I contrasted statements and expressions. Can
you possibly forgive me for my informal use of language?



> Therefore a 
> statement could have a value. But take this example:
> 
>   if cond1:   x=a1
>   elif cond2: x=a2
>   elif cond3: x=a3
>   else:       x=a4
> 
> Clearly this would be better expressed as (not valid Python):
> 
>    x = if cond1:   a1
>        elif cond2: a2
>        elif cond3: a3
>        else:       a4


x = a1 if cond1 else a2 if cond2 else a3 if cond3 else a4

We can split it over multiple lines too:

x = (
     a1 if cond1 else 
     a2 if cond2 else 
     a3 if cond3 else
     a4
     )


> (Actually 'del is a rather odd language feature. And I can't figure out
> how it's implemented; how does it manage 'del x[i]'? Anyway that's
> another matter.)


del x[i] calls x.__delitem__(i)



>> True if that allowed the value to be garbage
>> collected, False if it wasn't? Or the other way around? None of these
>> suggests feel either useful or obviously right.
> 
> It doesn't need to give a useful value.

Hence my suggestion that all statements (apart from expressions) return 42.


> Its 'value' lies in being able to have it in a sequence or block:
> 
>    z = del x; y

In a hypothetical Python where `del x` returns None, that would set z to
None and then evaluate y, doing nothing with the result.




-- 
Steven




More information about the Python-list mailing list