7

I am contemplating writing a programming language. Most grammars define expressions as being a kind of a statement. But really I cannot come up with a single example of any useful expression that would pass as a statement.

See https://stackoverflow.com/questions/19132/expression-versus-statement for an easy definition of expression vs statement.

EDIT: Why are so many grammars making the distinction between expr and stmt when as noted in the answers, it makes no sense.

4 Answers4

3

A function/method call is, of course, an expression. At the same time (in imperative programming languages, which I assume since you seem to take statements for granted) many functions have side effects and those side effects are often enough incentive to call the function. Consider functions like printf which exist primarily for their side effect and whose return value (in this case, number of chars printed) is usually not interesting. Or basically any function/method with no interesting return value -- i.e. void or () AKA unit. (While you could, in a statically-typed setting, differentiate between the two, doing so is entirely pointless.)

In languages with operator overloading, this extends to any expressions involving operators (read: almost all expressions), because these are basically functions as above, only called differently. Sometimes a bad idea, yes, but then there's embedded DSLs.

Also, if you make assignment an expression (bad idea IMHO, but rather common), you practically need it to also be valid as statement. Ditto for pre- and post-increment and -decrement -- these are expressions, yet mostly useful as standalone statements.

EDIT: As for why the distinction exists: Statements are distinct from expression so the grammar can prevent statements from being used as expressions. An example in Python: The "expression"

f(def g():
    pass
)

has multiple problems (primarily: does not work with the - otherwise great and simple - way indentation is handled; can be easily turned into a inner function definition) which make it utterly useless. For comparision, def g(): pass; f(g) is perfectly valid and sometimes (if f wants a callback and you want a no-op for that) useful. And not all languages accept every expression as statement -- many either rule out alternatives which never make sense (cf. Pascal, C#), or give a warning ("statement has no effect").

3

"What useful expressiveness will be impossible in a language where an expression is not a statement?"

None.

The definitions of "expression" and "statement" are largely arbitrary. Different languages define them differently. I know of no programming language whose way of defining these terms makes any particular construct impossible to express. In some languages, some constructs may be a bit more awkward; in others, it may be easier to write code that's difficult to read because a single statement depends on multiple side effects.

Almost all programming languages are Turing-complete and are able to express the same behaviors as any other Turing-complete languages.

Two good examples are Pascal and C.

In Pascal, an assignment is a statement, not an expression. A subroutine can be either a procedure (which doesn't return a value) or a function (which does). A procedure call is a statement, and cannot be part of an expression. A function call is an expression, and cannot appear in a statement unless you explicitly do something with the result, such as assigning it to a variable. Statements can contain expressions, but expressions cannot contain statements.

In C, an assignment is an expression. All subroutines are functions; functions that return no value are declared with a return type of void. A function call is an expression; it can be made into a statement by adding a semicolon. The result of a function call, or of any expression, can be silently discarded. Any expression can be turned into a statement by adding a semicolon. As in Pascal, statements can contain expressions, but expressions cannot contain statements (but gcc provides statement expressions as a language extension).

Here's a typical C construct that depends on the ability to treat assignments as expressions (item is some arbitrary type, and last_item is a constant of that type):

item x;
while ((x = get_next_item()) != last_item) {
    do_something_with(x);
}

In Pascal, you can implement exactly the same behavior like this (if I remember the syntax correctly):

var
    x: item;
    done: boolean = false;
begin
    while not done do
    begin
        x := Next_Item;
        if x = last_item then
            done := true
        else
            do_something_with(x);
    end;
end;
Keith Thompson
  • 6,442
  • 2
  • 30
  • 36
1

If you refer to the definitions that are provided on those pages, its easy to see why its difficult to come up with an expression that would pass as a statement.

Expression: Something which evaluates to a value. Example: 1+2/x

Statement: A line of code which does something. Example: GOTO 100

The expression is only the subject of the statement. If you're not assigning it to something in the end, then there's not a whole lot you can do with it.

You might want to look into lisp though.

0

Things like the traditional send call for sockets is a good example:

int send(int socket, char* buffer, int flags);

The 'bytes sent' return isn't strictly vital for the function to do its business.

You could of course say that not checking the bytes sent is an error and that your language should not allow that as input. The issue comes that parsing is done before the types are ever known. When parsing

send( socket, buffer, 0 );

your compiler has no idea if send returns a value or not. In most languages, that simple standalone expression is desirable to be allowed as a statement.

Telastyn
  • 110,259