Princeton University |
Computer Science 441 |
With commands must keep track of store: locations -> storable values.
If expressions can have side-effects then must update rules to keep track of effect on store. Rewriting rules now have conclusions of form (e, rho, s) >> (v, s') where v is a storable value, rho is an environment (mapping from identifiers to denotable values - including locations), s is initial state (or store), and s' is state after evaluation of e.
(b, rho, s) >> (true, s') (e1, rho, s') >> (v, s'') ------------------------------------------------------ (if b then e1 else e2, rho, s) >> (v, s'')Thus if evaluation of b and e1 have side-effects on memory, then show up in "answer".
Axioms - no hypotheses!
(id, rho, s) >> (s(loc), s) where loc = rho(id)Note s[loc:=v+1] is state, s', identical to s except s'(loc) = v+1.(id++, rho, s) >> (v, s[loc:=v+1]) where loc = rho(id), v = s(loc)
(e1, rho, s) >> (v1, s') (e2, rho, s') >> (v2, s'') ------------------------------------------------------ (e1 + e2, rho, s) >> (v1 + v2, s'')When evaluate a command, "result" is a state only.
E.g.,
(e, rho, s) >> (v, s') ------------------------------ where rho(x) = loc (x := e, rho, s) >> s'[loc:=v] (C1, rho, s) >> s' (C2, rho, s') >> s'' ------------------------------------------ (C1; C2, rho, s) >> s'' (b, rho, s) >> (true, s') (C1, rho, s') >> s'' ------------------------------------------------ (if b then C1 else C2, rho, s) >> s''+ similar rule if b false
(b, rho, s) >> (false, s') --------------------------- (while b do C, rho, s) >> s' (b, rho, s) >> (true, s') (C, rho, s') >> s'' (while b do C, rho, s'') >> s''' ------------------------------------------------ (while b do C, rho, s) >> s'''
Notice how similar definition of semantics for
while E do Cis to
if E then begin C; while E do C end
Distinction between what something does and how it does it.
Interested in supporting abstraction (separation between what and how).
Originally, designers attempted to create languages w/ all types and statements that were necessary.
Realized quickly that needed extensible languages.
First abstractions for statements and expressions - Procedures and Functions
Arrays and records, then pointers introduced to build new types and operations on them.
Built-in types have associated operations - representation is hidden (for most part)
Support of ADT's is most important innovation of 1970's.
Simula 67 - package op's w/ data types - representation not hidden
Clu, Mesa, Modula-2, Ada, Smalltalk
Come back to them in Chapter 8.
Iterators correspond to abstraction over control structure
- high-order fcns in ML even more so!
Book discusses selector abstractions: Calculate location rather than value.
More support for abstraction, generally more expressive is language.
Use of parameters supports abstraction -
Creates more flexible program
phrases.
Common, Global variables (in block-structured languages),
Parameters - data, subprograms, types
Access via indirection.
What if parameter is expression or constant? CHGTO4(2).
value (in), result (out), value-result (in-out)
result and value-result parameters must be variables, value can be any storable value.
Can be expensive for large parameters.
Ex.
Procedure swap(a, b : integer); var temp : integer; begin temp := a; a := b; b := temp end;Won't always work, e.g.
swap(i, a[i]) with i = 1, a[1] = 3, a[3] = 17.
No way to define a correct swap in Algol-60!
Expressive power - Jensen's device:
To compute: x = Sum for i=1 to n of Vi
real procedure SUM (k, lower, upper, ak); value lower, upper; integer k, lower, upper; real ak; begin real s; s := 0; for k := lower step 1 until upper do s := s + ak; sum := s end;
What is result of sum(i, 1, m, A[i])?
What about sum(i, 1, m, sum(j, 1, n, B[i,j]))?
If evaluating parameters has side-effects (e.g., read), then must know how and how many times parameter is evaluated to predict what will happen.
Therefore try to avoid call-by-name with expressions with side-effects.
Lazy evaluation is efficient implementation of call-by-name where only evaluate parameter once. Requires that there be no side-effects, since owise get diff. results.
Implement call-by-name using thunks - procedures which evaluate expressions - difficult and slow. Must pass around code for evaluating expression (including environment defined in). Can use the same THUNK's as show up in environment based interpreter.
Note different from call-by-text (which would allow capture of free vbles).
Can classify parameter passing by copying (value, result, or value-result) or definitional.
Definitional have constant, variable, procedural, and functional.
Constant parameters are treated as values, not variables - different from
call-by-value.
Default for Ada in parameters.
Can think of call-by-name as definitional with expression parameter.
Note that difference in parameter passing depends on what is bound (value or address) and when it is bound.
Already seen how to pass functional (& procedural) parameters in our interpreter using closures.
Often happens with global vbles
Also call by reference parameters, very dangerous in call-by-name.
Very disturbing in functions since can make it hard to figure out values of expressions. Example:
A[f(j)] := j * f(j) + jMakes it harder to optimize - e.g. evaluate f(j) only once.
Most common ways of arising: global and parameter, two parameters, pointers
Example:
Procedure swap( var x, y: integer); begin x := x + y; y := x - y; x := x - y end;
Tricky way of completing swap of x and y w/out extra space.
Doesn't always work - swap (a,a) (but does work with value-result! )
Can get similar probs with A, A[i] as parameters and pointers
Another problem: Overlap btn global vble and by-reference parameter.
Causes problems with correctness since any two vbles may refer to the same object.
Also makes it difficult to optimize if can't predict when a vble might be changed.
If no aliasing, can't detect difference btn call-by-reference and call-by-value-result.
But not semantically equivalent if aliasing is possible.
Leads to problems in Ada where language definition does not specify whether in-out parameters are to be implemented by reference or value-result.
(Illegal program if it makes a difference - but not detectable!)
Unfortunately Ada doesn't enforce no aliasing.
Therefore possible problems with in out parameters.
Euclid (variant of Pascal) designed to write verifiable programs.
Attempted to eliminate aliasing.
Unfortunately some can only be caught at run-time, e.g. p(A[i], A[j])
legality assertions generated to check run-time problems.
Global vbles had to be explicitly imported to avoid problems
i.e. treated as implicit parameters
Each parameter mechanism corresponds to declaration in language:
E.g., constant, variable (def. & declaration), procedure & function, type(?)