1

Why do we have the distinction between statements and expressions in most programming languages?

For example, in Java, assuming f and g return ints, this still won't compile because it's a statement and statements don't return values.

// won't compile
int i = if (pred) { 
    f(x); 
} else {
    g(x);
}

but in Scala, it's very happy with treating if as an expression.

// compiles fine
val i: Int = if (pred) f(x) else g(x)

So if there's no problem treating an if statement as an expression, why was there a distinction in the first place?

3
  • Lisp, Haskell, Ocaml don't have instructions (only expressions). And IIRC, the very first C compiler -or perhaps B- neither (but I may be wrong) Commented Aug 22, 2014 at 7:01
  • So what happens if I just write int i = if (pred) { f(x); }?
    – Simon B
    Commented Aug 22, 2014 at 11:14
  • @SimonBarker, that produces a type mismatch error at compile time. Commented Aug 22, 2014 at 13:05

2 Answers 2

0

The if could return a value here because both of the functions also return values. But there are void functions as well, and f and g might have different return types, which would make it unclear what the type of this if would be. In effect, if you ban statements from a programming language, you also ban void methods, strict typing and some more common constructs that a lot of people don't want to see go.

(And yes, I am aware that other people would be very glad to see them go and will tell me and you and everyone at great length and high volume how glad they would be - this is a Holy war, please don't fuel it.)

3
  • 1
    Why are you banning strict typing? Commented Aug 22, 2014 at 7:36
  • 1
    An if whose branches return different types is simply illegal in such a language. void methods don't exist, instead the unit type () is used which has a value (only a single, and hence meaningless, one) to be returned. And unless you pursue purely functional programming (in which case none of your concerns even arise), you will have a operator to "ignore" a value, i.e. execute an expression for side effects and then return (). Armed with that, you can trivially write if (c) { f(); } else { g(); } where f and g return different types and ; is the execute-and-ignore operator.
    – user7043
    Commented Aug 22, 2014 at 8:31
  • If f and g have different types, then the type of the if expression will be the most derived common supertype. Easy. Commented Aug 22, 2014 at 21:06
0

Because it is confusing, therefore it is easier to introduce bugs.

One of the most famous in C is: if (a = b) instead of if (a == b). With a distinction between expressions and statements, the compiler would have complained.

Going on with C, there is a specific form of if whenever it should return a value:

pred ? f(x) : g(x)
2
  • 1
    A distinction between expressions and statements doesn't necessarily help with if (a = b), as long as assignment is an expression (it's one in Java and C# which address this problem through other means). Making assignment a statement would help, but equally well one can restrict if to boolean values (Java, C#) and in a expression-oriented language, additionally make it the moral equivalent of a "statement": An expression that returns the unit type (), which is what Rust does.
    – user7043
    Commented Aug 22, 2014 at 8:24
  • 1
    @delnan - You are correct. In my mind an assignement is a statement, not an expression, i.e., let a take the current value of b, without the second part: and return that value.
    – mouviciel
    Commented Aug 22, 2014 at 8:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.