300 400 lineto".PRECEDENCE OPERATORS highest NOT . *, /, DIV, MOD, AND . +, -, OR lowest <, <=, <, >, =, >=, >, INNow, not only does C++ have many more operators, but it defines many more precedence levels. Too many precedence levels has the potential drawback that program behavior becomes difficult to predict without constantly referring to the precedence table. Too few levels can cause unexpected behavior. For example , in Pascal
x > y OR z > 0 is equivalent to x > (y OR z) > 0which is counterintuitive to say the least!
Issue: is assignment an expression or a
statment? I.e. will something like 3 + (x=5) be
allowed, and what will it mean? Java and C/C++ allow this,
which shows that assignements are expressions in
those languages. In the above, x=5 has the side
effect of assigning 5 to x, and the result of the
expression is simply x after the assignement. So the type
and value come directly from x. In SPL, we've defined
assignement to be a statement, so something like
write x := 5; is illegal. (Is this a lexical
error, parse error or an error in the semantic analysis
phase?) Python is similar. Assignment is a statement.
$ python
>>> x = 1
>>> print(x)
1
>>> print(x=2)
File "<stdin>", line 1
print(x=2)
^
SyntaxError: invalid syntax
In scheme, set! returns a void value, so you
can't really compute meaningfully with the return value of
a set!. Thus, in essence, assignment is not an
expression.
x = x + 1;is OK, but most likely
x + 1 = x;is not. Why? Why is x something that can be assigned a value but not x + 1? Why it doesn't work depends on your model of variables. The value model thinks of variables as locations that can hold values, and one assigns values to locations. So x is a location, but x + 1 is just a value. The object on the left-hand-side of the assignment must be what's called an
l-value, a
location. Objects that can appear on the right-hand-side,
i.e. "objects" or "values" are r-values. A
variable like x can play both roles. In "x = x + 1", the x on
the left stands for the location, the x on the right stands
for the value stored at that location. The other model is
the reference model. It views variables as being
references (pointers) to actual objects. In this model, the
problem with x + 1 = x is that x + 1
is not a reference. In the reference model, l-values are
locations that can hold references.
Python is an example of a language that follows the reference
model.
int x, y, z; cin >> x; (x > 0 ? y : z) = 10;... which tells us that the ?: operator yields (at least sometimes) l-values. C++ even lets you "return by reference", so that the results of function calls can be l-values.
int foo(int &m, int &n) { return (n > m ? n : m); }
int& bar(int &m, int &n) { return (n > m ? n : m); }
...
foo(x,y) = 5; // Error, foo(x,y) not an l-value
bar(x,y) = 5; // OK
Much less exotically, though, how about X[2*i+1] = 5;?
This should work, so clearly some expressions yield l-values.
Suppose you have a struct Point in C, with fields x and y of
type double. If p is a point, then p.x = 2.5; is
perfectly valid. So fields in structs are l-values.
The reason for this is that for basic types, the value model is more efficient. If x and y are ints, computing x+y in the value model requires fetching the value of x, fetching the value of y, and performing the addition. In the reference model, computing x+y requires fetching the address associated with reference x, then fetching the value from that address, doing the same two steps for y, and then adding. The extra round of memory accesses is costly - especially because it can be harder to ensure data locality, which means we lose out on some of the benefits of cache.
int a,b,c; a := 5; b := 2; c := a; a++;Under the value model c is still 5. Under the referenced model, if ++ really modifies the object a refers to, c now refers to 6. This is a bit counter to how we think of such things usually. With strings you have the same problem:
String a, b, c; a := "hello"; b := "goat"; c := a; a[0] := 'j';Now c refers to "jello". To avoid this in these fundamental types, systems with the reference model may make these types "immutable", i.e. unchangeable. This, ++ wouldn't modify the int a points to in the first example, it would create a new int and set a to point to it. The operation in the second example would be illegal. Functions for doing this kind of operation would actually return new strings. Since Java has the value model for int's, this doesn't come into play, but strings in Java follow the reference model, and they are indeed "immutable". Check out Why String is Immutable in Java? for a discussion of why Java chose to make string immutable.
BankAcct a = new BankAccount(); c = a; a.setBal(100);c's bank account is 100, because c and a refer to the same thing. Sometimes you really want copies, though, and Java has the
clonable interface to give a standard way of
getting duplicate objects. If BankAcct implements clonable,
we can do this:
BankAcct a = new BankAccount(); c = a.clone(); a.setBal(100);... and c's balance will still be zero ... or whatever the default is. Cloning is a commen operation when languages follow the reference model.