Download presentation
Presentation is loading. Please wait.
1
Assignments cs7100(Prasad) L13Assg
2
l-value vs. r-value Pascal/Ada: x := x + 1 C/Java: x = x + 1
l-value = location, address, reference, … r-value = int, real, (sometimes even) address, … Environment binds an identifier to a location. env : ids -> locations Store binds a location to a value. store : locations -> values assign-op : location x value x store -> store env and store allow one to describe the semantics of assignment in a purely functional style. (DENOTATIONAL SEMANTICS) On the other hand, the interpreter in Scheme use vector for the same purpose, for convenient implementation. Object language structures are mapped to similar Scheme structures. (META-CIRCULAR INTERPRETER) cs7100(Prasad) L13Assg
3
Sharing For functional subset, it is sufficient to model env as a function from ids to values. For imperative programming that has both assignment and sharing, separating env and store is necessary. E.g., sharing/aliasing Point p = new Point(); Point q = p; E.g., call by reference void f(Point p){}; f(q); a loc value x cs7100(Prasad) L13Assg
4
Side-effect causing Scheme primitives
Initialize variable: (define <var> <exp>) Update variable: (set! <var> <exp>) Other ops: display, write, set-car!, set-cdr!,... (set! x y) denotes location denotes value Sequencing: (begin <exp1> <exp2> … <expn>) In Scheme, locations are denotable, but not expressible. Ordering of expression evaluation important in the presence of side-effects. cs7100(Prasad) L13Assg
5
Extending object (not meta-) language and the interpreter to support variable assignment
cs7100(Prasad) L13Assg
6
Modifying environment and the interpreter
An identifier denotes the address of a mutable data structure that holds a value (that is, it models a memory location). This address is called a reference, and the contents of these references are modified by a variable assignment. Variable reference (var-exp (id) (deref (apply-env-ref env id))) l-value : aref – position – vector of values Implicitily, the implementation allocates storage for locals in let-construct and procedure-definition, and captures call-by-value parameter passing mechanism. Support for call by reference requires change to the interpreter. Support for multiple parameter passing mechanisms in the object language requires additional syntax. cs7100(Prasad) L13Assg
7
Refer to full interpreter code for contextual details
(define-datatype reference reference? (a-ref (position integer?) (vec vector?))) (define deref (lambda (ref) (cases reference ref (a-ref (pos vec) (vector-ref vec pos))))) (define setref! (lambda (ref val) (vector-set! vec pos val))) 1)) Refer to full interpreter code for contextual details A reference is an entire vector plus a position. cs7100(Prasad) L13Assg
8
Refer to full interpreter code for contextual details
(define apply-env-ref (lambda (env sym) (cases environment env (empty-env-record () (eopl:error 'apply-env-ref "No binding for ~s" sym) ) (extended-env-record (syms vals env) (let ((pos (rib-find-position sym syms))) (if (number? pos) (a-ref pos vals) (apply-env-ref env sym))))))) (define apply-env (deref (apply-env-ref env sym)))) Refer to full interpreter code for contextual details Appy-env-ref returns an aref (position + vector) cs7100(Prasad) L13Assg
9
Refer to full interpreter code for contextual details
(define extend-env-recursively (lambda (proc-names idss bodies old-env) (let ((len (length proc-names))) (let ((vec (make-vector len))) (let ((env (extended-env-record proc-names vec old-env))) (for-each (lambda (pos ids body) (vector-set! vec pos (closure ids body env))) (iota len) idss bodies) env))))) The mutually recursively procedures are bound to the right closures in the vector. Refer to full interpreter code for contextual details cs7100(Prasad) L13Assg
10
Introduction of variable assignment
Syntax <expression> ::= set <identifier> = <expression> Abstract Syntax varassign-exp (id rhs-exp) Semantics (varassign-exp (var exp) (set-ref! (apply-env-ref env var) (eval-expression exp env) ) ) l-value r-value The semantics of “set x = x” will clarify the distinction between l-value and r-value. In main stream languages, the coercion (dereferencing) is implicit, while in languages such as ML, it is explicit. E.g., in C, we can write the assignment “int x = 5; x = x;”, while in ML the corresponding code is “val x = ref 5; x = !x;” cs7100(Prasad) L13Assg
11
Simulating letrec using let and assignment
(letrec ((var1 exp1) (var2 exp2)) exp ) (* exp1 and exp2 are lambda-forms *) (let ((var1 ’*) (var2 ’*)) (set! var1 exp1) (set! var2 exp2) let and assignment in the object language can allow us to simulate letrec, but only in the context of procedural values. (letrec ( (x (lambda () y)) (y 1) ) (x) ) = but (letrec ( (x y) (y 1) ) x ) = error cs7100(Prasad) L13Assg
12
Simulating Objects and Classes
cs7100(Prasad) L13Assg
13
Defining a stack object
(define empty? '()) (define push! '()) (define pop! '()) (define top '()) (let ( (stk '()) ) (set! empty? (lambda() (null? stk))) (set! push! (lambda(x) (set! stk (cons x stk)))) (set! pop! (lambda() (set! stk (cdr stk)))) (set! top (lambda() (car stk))) ) One stack object. Representation private.(encapsulation) Methods public, in fact, global. Illustrates the independence of scope and lifetime: limited scope, infinite lifetime. (let ( (stk '()) ) (define empty? (lambda() (null? stk))) (define push! (lambda(x) (set! stk (cons x stk)))) (define pop! (lambda() (set! stk (cdr stk)))) (define top (lambda() (car stk))) ) This definition is incorrect because methods are local, not global. Quote character is ’ and not ‘ or ’ cs7100(Prasad) L13Assg
14
Using the stack object > (empty?) #t > (push! 5) > (top) 5
> (pop!) Only one stack object. Scope of stk is limited (encapsulation), but its lifetime is not. representation pvt. methods public. Persistent state. Ops. share data and change state. Note how the ability to restrict visibility using let-construct and using assignment operation, it is possible to encode objects (with state). cs7100(Prasad) L13Assg
15
stack object : Message passing style
(define stack (let ( (stk '()) ) (lambda (msg) (case msg ((empty?) (lambda () (null? stk)) ) (( push!) (lambda (x) (set! stk (cons x stk))) ) (( pop! ) (lambda () (set! stk (cdr stk))) ) ((top) (lambda () (car stk)) ) (else 'error ) ) ))) In the previous case, the methods are global and the second stack instance must support a differently named global methods, to avoid name clashes. In order to make stack objects respond to same methods, that is share a common interface, one can recast it using message passing style. Quote character is ' and not ‘ or ’ cs7100(Prasad) L13Assg
16
Object vs. Class (define s1 (make-stack)) > ((stack 'empty?))
((s1 'push!) 1) ((s2 'push!) 2) ( (s1 'top) ) 1 ( (s2 'top) ) 2 > (stack 'empty?) > ((stack 'empty?)) #t > ((stack 'push!) 5) > ((stack 'top)) 5 > ((stack 'empty?)) () or #f > ((stack 'pop!)) let-construct, thunks, procedures and assignment are the basic ingredients required to support OOP style of programming. cs7100(Prasad) L13Assg
17
Instance/Object vs. Class/Type
(define stack (let ((stk '()) ) (lambda (msg) (case msg ... ) )) (define make-stack (lambda() (let ((stk '()) ) (lambda (msg) (case msg ... ) )) When stack is defined, stk is allocated. To delay allocation, one can use thunk. Each time the thunk is evaluated, a new incarnation of stk corresponding to a new instance is created. cs7100(Prasad) L13Assg
18
stack class : Message passing style
(define make-stack (lambda () (let ( (stk '()) ) (lambda (msg) (case msg ((empty?) (lambda () (null? stk)) ) (( push!) (lambda (x) (set! stk (cons x stk))) ) (( pop! ) (lambda () (set! stk (cdr stk))) ) ((top) (lambda () (car stk)) ) (else 'error ) ))) ) The two invocations of (makestack) result in two different private mini-environments for stk. However, does the two invocations share the resulting procedure codes? (cf. conventional classes) cs7100(Prasad) L13Assg
19
Template for class definition
(define class-name (let ((class-var val)) (lambda () (let ((inst-var val)) (lambda (msg) (case msg ((m1) code) ((m2) code) ((c3) code) (else ’error) )) ) ) ) ) Illustrates: classes ; class variables, instances, instance variables, class methods, instance methods. How do we enable class methods independent of an instance in this setting? One approach: bind class name to (lambda (classmsg) …) value with “new” message allocating storage and initializing the instance, and other messages invoking class methods. In this case, instances will not respond to class messages, unless they are explicitly delegated to it. cs7100(Prasad) L13Assg
20
(define make-stack (let ((pushed 0)) (lambda () (let ((stk '()) (local-pushed 0) ) (lambda (message) (case message ((empty?) (lambda () (null? stk))) ((push!) (lambda (x) (set! pushed (+ pushed 1)) (set! local-pushed (+ local-pushed 1)) (set! stk (cons x stk)))) ((pop!) (lambda () (if (null? stk) (error "Stack: Underflow") (begin (set! pushed (- pushed 1)) (set! local-pushed (- local-pushed 1)) (set! stk (cdr stk)))))) ((top) (lambda () (car stk)))) ((local-pushed) (lambda () local-pushed)) ((pushed) (lambda () pushed)) (else (error "Stack: Invalid message" message))))) ))) Illustrates classes ; class variables, instances, instance variables, class methods, instance methods. How do we enable class methods independent of an instance in this setting? One approach: bind class name to (lambda (classmsg) …) value with “new” message allocating storage and initializing the instance, and other messages invoking class methods. In this case, instances will not respond to class messages, unless they are explicitly delegated to it. cs7100(Prasad) L13Assg
21
make-stack (lambda () (let (…) … ) pushed = 0
(make-stack) (make-stack) (lambda (msg) … ) stk = () local-pushed = 0 (lambda (msg) … ) stk = () local-pushed = 0 cs7100(Prasad) L13Assg
22
Rewrite in Java public class Stackclass { static int pushed;
private Vector stk; private int localpushed; static { pushed := 0 } public Stackclass(){ localpushed = 0; stk = new Vector(); } public boolean empty() { return stk.isEmpty() }; public void push(Object x){ pushed++; localpushed++; stk.addElement(x); } Here pushed can be made “private” for now, and changed to “protected” later. Scheme uses list, while Java uses vector APIs to implement “unbounded” stacks. (Recall that Scheme’s built-in vectors are akin to heterogeneous arrays.) cs7100(Prasad) L13Assg
23
throw new Exception(“Stack Empty”); else { --pushed; --localpushed;
... public void pop(){ if (stk.isEmpty()) throw new Exception(“Stack Empty”); else { --pushed; --localpushed; stk.removeElementAt(stk.size()-1); } public Object top(){ if (empty()) throw new Exception(“Stack Empty”); else return stk.lastElement(); public int pushed() { return pushed; } public int localpushed(){ return localpushed; } cs7100(Prasad) L13Assg
24
Approximate Environment
Approximate because the diagram has additional empty boxes after class-var and class-val. Fix: Place a cross in the empty class-var box and view class-val box as signifying a vector. Interpret = Compile + Run Similarly, Run-time Class-Instance Structures = Symbol table Heap (not activation records) * Environment * *Store* compile-time entity run-time entity Note that stack instances will be vector of values, while the class contains instance fields, class env, and method table. cs7100(Prasad) L13Assg
25
Rewrite in Java Stackclass stack1 = new Stackclass();
public class Test { public static void main(String [] args) { Stackclass stack1 = new Stackclass(); stack1.push(new Integer(7)); stack1.top(); stack2.push(new Integer(6)); stack2.push(new Integer(8)); stack2.top(); stack1.localpushed(); stack2.localpushed(); stack1.pushed(); stack2.pushed(); } If the method definition contains n-formals, the method call will take (n+1) arguments because it makes explicit the receiver. cs7100(Prasad) L13Assg
26
Approximate Environment
Approximation: Extra boxes in the diagram. Result after the following evaluations: --> define stack1 = simpleinstance(stackclass) --> define stack2 = simpleinstance(stackclass) --> $push(stack1, 7) cs7100(Prasad) L13Assg
27
Inheritance Share and reuse classes with modifications to fields and methods Improve programmer productivity and aid code evolution Classes provide an organization for the objects in the language. Inheritance and composition are two kinds of relationships among classes. cs7100(Prasad) L13Assg
28
Inheritance in Java Specify only incremental changes.
class Boundedstackclass extends Stack { private int bound; Boundedstackclass() { super(); bound = 10; } public void push(Object x) { if (size() < bound) super.push(x); else new Exception(“Overflow”); public void setbound(int x){ bound = x; Specify only incremental changes. Access parent’s version of a method through super. “ cs7100(Prasad) L13Assg
29
Composition and Delegation in Java
class Boundedstackclass { private int bound; private Stack stk; Boundedstackclass() { stk = new Stack(); bound = 10; } public void push(Object x) { if (size() < bound) stk.push(x); else new Exception(”Overflow”); public void setbound(int x){ bound = x; public Object top() { return stk.top(); ... Explicit list of other delegated stack methods Not as convenient as in message passing style. To simulate that we need to pass a message name and have a switch statement. Delegated message is not dispatched automatically; it requires a small stub code “to pass the buck”. Multiple automatic delegation has similar problems as multiple inheritance. cs7100(Prasad) L13Assg
30
Delegation (define make-bounded-stack (lambda (n)
(let ((bound n) (stk (make-stack))) (lambda (message) (case message ((push!) (if (< ((stk 'local-pushed)) bound) (stk 'push!) (error “Overflow”))) ((set-bound!) (lambda (x) (set! bound x))) ((set-stack!) (lambda (s) (set! stk s))) (else (stk message)) ) )))) Typically, the inherited fields are fixed. All bounded stacks will inherit fields in the parent stack class. Composition and delegation enables substituting objects with same interfaces at run-time. These objects may potentially have different representations. ; (((make-bounded-stack 24) 'top)) cs7100(Prasad) L13Assg
31
Delegation (define stk (make-bounded-stack 24)) ( (stk 'push!) 3)
( (stk 'top) ) (((make-bounded-stack 24) 'push!) 3) ; (((make-bounded-stack 24) 'top)) Typically, the inherited fields are fixed. All bounded stacks will inherit fields in the parent stack class. Composition and delegation enables substituting objects with same interfaces at run-time. These objects may potentially have different representations. ; (((make-bounded-stack 24) 'top)) cs7100(Prasad) L13Assg
32
Delegation vs Inheritance
Code sharing by organization of objects. Delegate message handling. Dynamic and flexible. When and how to delegate can depend on system state. E.g., Java 1.1 Event Model Code sharing by organization of classes. Single vs multiple inheritance. Static but efficient. Type determines message interpretation. E.g., Java 1.0 Event Model For all practical purposes, inheritance can be approximated well using delegation and composition. Given that there is no one way to resolve inheritance conflicts in the context of a DAG class structure, composition and delegation provides a nice mechanism to approximate multiple inheritance of code as illustrated in Java. Fundamental differences show up only when you consider polymorphism issues and updates to public fields and methods. (See our paper in “Computer Languages”.) cs7100(Prasad) L13Assg
33
Scoping: Lexical vs Static
class A { static int cv; int iv; } class Test { public static void main(String [] args){ int iv, cv; class B extends A { void print() { System.out.print( “”+ cv + iv ); /*error*/ System.out.println( “”+this.cv +this.iv ); new B(). print(); A.java:9: Variable 'cv’ and ‘iv’ are inherited in local class B (Test. 1$B), and hides a local variable of the same name. An explicit 'this' qualifier must be used to select the variable, or the local must be renamed. System.out.print( ""+ cv + iv ); ========================================================================== JDK 1.0: local variables hide fields. So use “this” for disambiguation. JDK 2.0: access local variables via renaming. Use “this” for fields. NO DEFAULTS. Language design approaches to resolve name conflicts due to multiple definitions due to enclosing class/method and ancestor classes: Both definition meaningful 1.1 Choose one as the default and provide syntactic sugar to get to the other. 1.2 Require the user to always pick one over the other. 2. One definition more appropriate than the other. 2.1 Choose that and ban the other. 2.2 Force user to explicitly pick the appropriate one for pragmatic reasons: minimizing potential errors due to oversight. ===================================================== Typically local variables hide the fields. Any relation to allocating locals on stack and objects on heaps (cf. threads)???? cs7100(Prasad) L13Assg
34
Binding: Dynamic vs Static
class A { static int cv = 10; int iv = 70; int f() {return 40;} void print() { System.out.println( “”+ cv + iv + f()); }} class B extends A { static int cv = 33 ; int iv = 88; int f() {return 55;} } class Test2 { public static void main(String [] args){ new A(). print(); new B(). print(); Parent static/instance fields hidden in the event of name conflicts. However, instance methods are dynamically bound. cs7100(Prasad) L13Assg
35
Advanced Topics Multiple Inheritance Meta-classes Inner/Nested classes
E.g., C++, Eiffel. Meta-classes E.g., Smalltalk. Inner/Nested classes E.g., Java. Polymorphic Static Typing E.g., ML, Haskell. cs7100(Prasad) L13Assg
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.