Download presentation
Presentation is loading. Please wait.
Published byNeil Gregory Modified over 8 years ago
1
1 Objects and types Typed languages = define a set of types in the language and assign a type to each expression in the program Type checking = how can we implement a simple type checker for a static typing language Do type checking in an OO language State design decisions for implementing a Type Checker (TC)
2
2 Design principles for our TC 1. Type checking for any language, not only OOL Define a set of types for the language and define what means for a value v to be of type t. If an expression e is assigned type t, then whenever e is executed, its value will be of type t. No program that passes the checker will ever attempt to apply a non-procedure to an argument No program that passes the checker will ever attempt to apply a procedure or primitive to the wrong number of arguments or to an argument of the wrong type
3
3 Design principles for our TC 2. Type checking for an OOL Fields in classes and methods are specified with their types, similar with what we shall do for the “any language” TC The concepts of abstract classes and abstract methods are introduced The concept of casting is introduced and the instanceof test The concept of subtype polymorphism is added to the language No program that passes the TC will ever send a message to an object for which there is no corresponding concrete method No program that passes the TC will ever send a message to an object with the wrong number of arguments or with arguments of the wrong type
4
1.1 Type specification in our language A method to assign types to expressions and checking that no expression can possibly cause an operation to be performed on inappropriate arguments. The TC either produces a type for the program or reject it and reports an error. Types in the language ::= int int-type-exp ( ) ::= bool bool-type-exp ( ) ::= ({ }*(*) - > ) proc-type-exp (arg-texp result-texp) Examples (int * int - > int)type of + (int - > (int - > int ))type of (lambda (x) (lambda (y) (+ x y))) The language will be strongly statically typed. 1. Type checking for a restricted (ordinary) language
5
A type error in the language is defined as one of the following: An attempt to apply an integer or a boolean to an argument An attempt to apply a procedure or primitive to the wrong number of arguments An attempt to apply a primitive expecting an integer to a non-integer An attempt to use a non-boolean as the test in a conditional expression TC The TC will mainly consist of a procedure: type-of-expression, based on the following idea: it will have the same structure as eval-expression but, instead of evaluating each expression in an environment containing the values of variables (env), it will process each expression in a type environment (tenv) containing the types of the variables. type-expression has thus the following goal: when given an expression exp and a type environment tenv mapping eac variable to a type, it assigns to exp a type t with the property that: –whenever exp is executed in an environment in which each variable has the type specified in tenv, the resulting value has the type t. Premisis: if we know the type of the value of each of the variables in an expression, we can deduce the type of the value of the expression. This type will be the type of the expression 5
6
We shall consider the following features in the language: numbers, variables, if expressions, procedure expressions, primitive application, operator application, let expressions and associate the previously mentioned types. In order to determine the resulting type of these expressions we will use Typing Rules = a standard way to specifying the typing behaviour of a language. Behavior of type-of-expression Number (type-of-expression tenv) = int Variable (type-of-expression tenv) = (apply-env tenv id) Conditional specification (type-of-expression tenv) = bool (type-of-expression tenv) = t 6
7
Primitive application (rator rand1 …. randn)(t1 * t2 * … * tn) -> t if (type-of-expression tenv) = (t1 * t2 * … * tn) -> t and (type-of-expression tenv) = t1 ……. and (type-of-expression tenv) = tn then (type-of-expression tenv) = t Procedure expression proc (x1, x2, …, xn) exp(t1 * t2 * … * tn) -> t ? (type-of-expression [x1=t1, …, xn=tn] tenv) = t (type-of-expression tenv) = (t1 * t2 * … * tn) -> t Let expression if (type-of-expression tenv) = t1 and (type-of-expression tenv) = t2 … and (type-of-expression tenv) = tn and (type-of-expression [x1=t1, …, xn=tn] tenv) = t then (type-of-expression tenv) = t 7
8
8 Problem: if we are trying to compute the type of a procedure expression, how are we going to find the types t1, …, tn of the bound variables? Two solutions: Type checking : the programer must supply the missing information about the types of bound variables and the TC deduces the types of the other expressions and checks them for consistency Type inference : the TC attempts to infer the types of the bound variables based on how variables are used in the program. 1.2 Type checking We require the programmer to include the types of all bound variables A procedure expression will look like: proc (t1 x1, t2 x2, …., tn xn) exp ::= proc ({ }* (,) ) ::= true | false
9
(define type-of-expression (lambda (exp tenv) (cases expression exp (lit-exp (number) int-type) (true-exp () bool-type) (false-exp () bool-type) (var-exp (id) (apply-tenv tenv id)) (if-exp (test-exp true-exp false-exp) (let ((test-type (type-of-expression test-exp tenv)) (false-type (type-of-expression false-exp tenv)) (true-type (type-of-expression true-exp tenv))) (check-equal-type! test-type bool-type test-exp) ;^ these tests either succeed or raise an error (check-equal-type! true-type false-type exp) true-type)) ----- see next slide -------- (Figure 4.5 EPL) 9 (define-datatype type type? (atomic-type (name symbol?)) (proc-type (arg-types (list-of type?)) (result-type type?))) (define expand-type-expression (lambda (texp) (cases type-exp texp (int-type-exp () int-type) (bool-type-exp () bool-type) (proc-type-exp (arg-texps result-texp) (proc-type (expand-type-expressions arg-texps) (expand-type-expression result-texp)))))) (define expand-type-expressions (lambda (texps) (map expand-type-expression texps))) (Figure 4.3 EPL)
10
(define type-of-expression (lambda (exp tenv) (cases expression exp ……… continued (proc-exp (texps ids body) (type-of-proc-exp texps ids body tenv)) (primapp-exp (prim rands) (type-of-application (type-of-primitive prim) (types-of-expressions rands tenv) prim rands exp)) (app-exp (rator rands) (type-of-application (type-of-expression rator tenv) (types-of-expressions rands tenv) rator rands exp)) (let-exp (ids rands body) (type-of-let-exp ids rands body tenv)) ))) type-of-proc-exp It first converts t1,.., tn into a list of types It then checks the bod y of the procedure in the type environment and binds the resulting type to result-type last, it constructs a procedure type, corresponding to (t1 * t2 * … * tn) -> t following the specifications of the typing rules. type-of-application It first checks to see if the type of the operator is a procedure type It then checks to see if the number of arguments expected by the procedure matches the no. of arguments supplied Then, for each assignment, it checks if the type of the argument is equal to the type of the corresponding operand Then, if everything is OK, the type of the application is the result type of the procedure type-of-primitive takes a primitive and returns its type 10
11
11 2. Type checking for an OOL 2.1 Type specification in a simple typed OOL New features of the language: Add a void type as the type of a set operation Add list types to return composite results An identifier used as a type is associated with the class of the same name Classes take an optional abstract specifier Methods require their result type to be specified, along with the types of their arguments Abstract class – a class which will not be instantiated. This restriction can be neforced by a run-time check whenever a new object is created. See difference concrete class Abstract method – a placeholder for a method to be supplied by each subclass of a class. Not applied but verified in every concrete class.
12
New features of the language - continued: Instanceof : instanceof exp class – checks if the object obtained by evaluating exp is an instance of class or of one of its descendants. Returns true or false Cast : cast exp class – checks if the object exp is an instance of class and returns the object or an error Subtype polymorphism – objects in a certain class can be regarded as instances of any of the ancestors classes of that class. To cope with these modifications we need: - modifications to method declaration processing - modifications to the evaluation of expressions See Figure 6.2 EPL for concrete and abstract syntax of this language Modifications to method declaration Datatype method-decl a-method-declresult-texp, name, arg-type-exps, ids, method-body an-abstract-method-declresult-texp, name, arg-type-exps, ids 12
13
abstract class tree extends object method int initialize ( ) 1 abstract method int sum ( ) abstract method bool equal (tree t) class interior_node extends tree field tree left field tree right method void initialize (tree l, tree r) begin set left = l; set right = r end method tree getleft ( ) left method tree getright ( ) right method int sum ( ) +(send left sum( ), send right sum ( )) method bool equal (tree t) if instanceof t interior-node then if send left equal (send cast t interior_node getleft ( )) then send right equal (send cast t interior_node getright ( )) else false class leaf_node extends tree field int value method void initialize (int v) set value = v method int sum ( ) value method int getvalue ( ) value method bool equal (tree t) if instanceof t leaf-node then zero? (- (value, send cast t leaf_node getvalue ( ))) else false let o1 = new interior_node (new interior_node (new leaf_node (3), new leaf_node (4)), new leaf_node (5)) in list (send o1 sum( ), if send o1 equal(o1) then 100 else 200) 13
14
Modifications to apply-method (define apply-method (lambda (method host-name self args) (let ((ids (method->ids method)) (body (method->body method)) (super-name (method->super-name method)) (field-ids (method->field-ids method)) (fields (object->fields self))) (eval-expression body (extend-env (cons '%super (cons 'self ids)) (cons super-name (cons self args)) (extend-env-refs field-ids fields (empty-env))))))) 14
15
Modifications to eval-expression (cast-exp (exp name) (let ((obj (eval-expression exp env))) (if (is-subclass? (object->class-name obj) name) obj (eopl:error 'eval-expression "Can't cast object to type ~s:~%~s")))) (instanceof-exp (exp name) (let ((obj (eval-expression exp env))) (if (is-subclass? (object->class-name obj) name) the-true-value the-false-value))) 15
16
16 2.2 The type checker Goal of the type checker = no program that passes the TC will ever: Snd a essage to an object for which there is no corresponding method Send a message to an object with the wrong number of arguments or with arguments of the wrong type Attempt to create an object of an abstract class, or an object of a concrete class in which one of the required abstract methods of a superclass has not been supplied (comments on initialiaze) TC The TC will mainly consist of a procedure: type-of-expression, based on the following idea: it will have the same structure as eval-expression but, instead of evaluating each expression in an environment containing the values of variables (env), it will process each expression in a type environment (tenv) containing the types of the variables.
17
In an OO paradigm we have two competing notions: -Types -Classes -Can we consider the class of an object as the type of that object? Policy: we introduce a type c for each class c and say that an object is a value of type c whenever its class is either c or a class that is a subclass of c (define-datatype type type? (atomic-type (name symbol?)) (list-type (value-type type?)) (class-type (name symbol?)) (proc-type (arg-types (list-of type?)) (result-type type?)))17
18
(define type-of-program (lambda (pgm) (cases program pgm (a-program (c-decls exp) (statically-elaborate-class-decls! c-decls) (type-of-expression exp (empty-tenv)))))) statically-elaborate-class-decls! Processes a class declaration and builds a static class environment. This environment will be used by type-of-expression The static class enviroment is like an ordinary class environment + the types of the method fields, the types of the methods and its parents A class contains all the fields and methods accessible from that class. For each method we construct a static method. Statically-roll-up-method-decls and statically-merge-methods produce a list of static methods, taking inheritance into account. Methods are placed in order of declaration. If a method of an ancestor class is overriden, the newer method is installed in place of the ancestor method. Hence, in each class there is at most one method for each method name. Exception: initialize 18
19
Then the static class information is added to the static class environment by add-to-static- class-env! Then each of the method declarations is checked using typechecked-method-decl! Which builds a type environment that matches the runtime environment built by apply-method. (define typecheck-method-decl! (lambda (m-decl self-name super-name field-ids field-types) (cases method-decl m-decl (a-method-decl (result-texp name id-texps ids body) (let ((id-types (expand-type-expressions id-texps))) (let ((tenv (extend-tenv (cons '%super (cons 'self ids)) (cons (class-type super-name) (cons (class-type self-name) id-types)) (extend-tenv field-ids field-types (empty-tenv))))) (let ((body-type (type-of-expression body tenv))) (check-is-subtype! body-type (expand-type-expression result-texp) m-decl))))) (an-abstract-method-decl (result-texp name id-texps ids) #t)))) 19
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.