Orthogonality

Features can be used in any combination.

Example:

Algol-orthogonality was major design goal. Expression oriented; no separate notion of statements

begin
a := if b < c then d else e; // rhs is expression
a := begin f(b); g(c) end;   // value of rhs is g(c), rhs is a statement though
g(d);						 // return value of g(d) thrown away
2 + 3;                       // value of code block
end

Even the entire above block is an expression, and its return value is 5.

In Java, b < c ? d : e is equivalent- returns a value.

C takes an intermediate approach.

  • distinguishes between statements and expressions
  • one class of expression is expression statement, which computes the value of expression and throws it away.
  • assignments can appear in expressions
  • in any context that expects a boolean, C accepts anything that can be coerced into an int

Other features

  • Combinational assignment operators such as += and *=
  • Multiway assignment such as a,b,c := d,e,f. Allows functions to return multiple values

Initialization

Specifying initial value of a variable in its declaration. Initial value of statically allocated variables can be set by compiler.

Orthogonality requires a way to initialize composite types. Only saves time for statically allocated variables. Other initialization is done at runtime.

Definite Assignment

Require that a value be “definitely assigned” to a variable before the variable is used in any expression. Every possible control path to an expression must assign a value to every variable in the expression. This is the case in Java and C# for all but local variables in a subroutine.

Dynamic checks can fail as semantic errors at runtime. Expose some subtle bugs that could exist with compiler supplying default values. Happens in C++.

Ordering within expressions

(a + b) * (c + d)? Most languages do not specify order, allowing compiler to choose. Java and C# require left-to-right.

Mathematical Identities

  • commutativity is assumed to be safe
  • associativity (known to be dangerous)
    • (a + b) = c works if a=maxint and b=minint and c < 0
    • a + (b + c) does not
  • inviolability of parantheses (language RESPEKS parantheses)

Short circuit evaluation

  • a(x) && b(y) - can evaluate left to right, and stop if a(x) if false
  • a(x) || b(y) - no point in evaluating b(y) if a(x) is true
  • this is often more efficient
  • Changes semantics, e.g., if (z != null && z.w > 0)
  • If subexpressions have side effects, short circuits may not be desireable. Ada does both!

Sequence points

C, C++ define “sequence points” that constrain order of evaluation. Between SPs, order is unconstrained. There are few SPs, which can lead to unpleasant surprises. For e.g.,

  • At the end of a full expression, terminated usually by ;
  • after eval of all fn args in a fn call and before execution of any exprs in the fn body
  • after cpying of a rtrnd value and before execution of any exprs outside the fn
  • after evaluation of the first exprsn in a&&b, a||b, a?b:c, or a,b
  • after the init of each base and member in the constructor init list

Example:

Assume i has value 1 before the expression

x[i] = i++ + 1

Don’t know if we are storing at x[1] or x[2]!

Example:

Assume i==1, j==2

f(i++, j++, i+j)

In C, don’t know what gets passed to f in the 3rd parameter. No sequence points constrain the order of evaluation of these args