﻿




We shall deal with Statically, class-based, typed O.O. languages 
(we previously referred to them simply as "strongly typed")






Many advantages to having a statically type-checked language:

** providing earlier, and usually more accurate, 
   information on programmer errors

** eliminating the need for run-time type checks
   that can slow program execution and increase program size

** providing documentation on the interfaces of components 
   (e.g., procedures, functions, and packages or modules)

** providing extra information that can be used in compiler 
   optimizations.






As a result most modern languages have static type systems



Of course, the more flexible, the better!


standard PASCAL: "inflexible" type system 
(sorting non working for arrays of different sizes)








In between static and dynamic  (in Theta)

x:S

typecase x
   when T(t): ... t ...
   when U(u): ... u ...
   others: ... x ...
end;


(in case T<:S and U<:S)






Cast in Java not statically type-safe 
(seen in FJ)













Many type problems and rigidities present in
in statically typed object-oriented languages



mainly because of

** conflation of type with class 

** mismatch of the inheritance hierarchy with subtyping


Goal:
Understanding the problems, hinting at solutions.










We start by reviewing some relevant concepts in OO languages




Objects encapsulate both state and behavior.

 An OBJECT:  

INSTANCE VARIABLES

and 


METHODS

method invokation: message sending









We assume objects are references

then

Sharing Semantics for assignment
(as in Java and Smalltalk)









CLASSES:
extensible templates for creating objects, 
providing initial values for instance variables and 
the bodies for methods.


All objects generated from the same class share the same methods, 
but
contain separate copies of the instance variables. 










Example of notation we shall use

class CellClass {
   x: Integer := 0;

   function get(): Integer is
   { return self.x }

   function set(nuVal:Integer): Void is
   { self.x := nuVal }
 
   function bump(): Void is
  { self <= set(self <= get()+1) }
}





"self" is "this" in Java

<= to send messages

In many language self is omitted











We assume:

instance variables  are not accessible from outside of that object's
methods. 

methods are by default publicly accessible from outside of the object











In many languages,  a class name is 

** name for the class

** name for constructor

** name for the type of the objects


better not to conflate these uses










ObjectType  { m_1 : T_1, ... m_n : T_n }


















CellType = ObjectType  { get: Void -> Integer;
                         set: Integer -> Void;
                         bump: Void -> Void }













Object Types do not mention instance variable, since they are not
publicly accessible!
















class DimCellClass {
   z:Integer := -1;
   
   function get(): Integer is
   { return self.z + 1 }

   function set(nuVal:Integer): Void is
   { self.z := nuVal - 1 }

  function bump(): Void is
  { self <= set(self <= get()+1) }
}






Same ObjectType

















dynamic method invocation:



the object receiving a message is responsible for
knowing which method body to execute 
(a mechanism enhancing flexibility)


















program CellExample;
   ... // Definitions of CellClass, DimCellClass,
       // and CellType omitted
var
    c: CellType := nil;     // (1)
{
    c := new CellClass;     // (2)
    c <= set(17);           // (3) set from CellClass
    c <= bump();            // (4)
    writeln(c <= get());    // (5)
    c := new DimCellClass;  // (6)
    c <= set(17);           // (7) set from DimCellClass
    c <= bump();            // (8)
    writeln(c <= get())     // (9)
}





Subclasses: they inherit and (possibly) modify



class ClrCellClass inherits CellClass modifies set {

    color:ColorType := blue;
 
    function getColor(): ColorType is
    { return self.color }

    function set(nuVal:int): Void is
    { self.x := nuVal;
    self.color := red }
}






ClrCellType =
   ObjectType { get: Void -> Integer;
                set: Integer -> Void;
                bump: Void -> Void;
                getColor: Void -> ColorType
}










Using "super" the set method could be

{ super <= set(nuVal);
  self.color := red }











Dynamic method invocation plays an important role during inheritance













K.Bruce use the "substitutability" intuition for subtyping:

"We say type T is a subtype of U, written T <: U, if a value 
of type T can be
used in any context in which a value of type U is expected."




















The subsumption rule introduce a sort of polymorphism in languages
with subtyping:

Subtype Polymorphism


ClrCellType <: CellType


We use Structural Subtyping


Good motivations to use it instead of Nominal Subtyping 
(see Venneri's slides)















Subtyping is a matter of types

Inheritance of "implementations"



>> No necessity to restrict subtyping to those relationships 
   arising froms subclasses
   (uselessly restrictive)

>> Besides, in reasonable languages a class may inherit from onother
   BUT the type of its objects not necessarily being a subtype








class C {
    v: T1 := ...;

    function m(p: T2): T3 is { ... }
}


class SC inherits C modifies v, m {
    v: T1' := ...;
 
    function m(p: T2'): T3' is { ... }
}





Which conditions over types in order to define subclasses
mantaining type safeness?






For method types:
the restrictions (that we know) imposed by the definition
of <: for record types.

ObjectType { ...
             m : T2 -> T3
             ...
           }


         <: (how we define <: in order to preserve type safety?)

ObjectType { ...
             m : T2' -> T3'
             ...
           }









But what about types of instance variables 
when defining subclasses? 
T1=T1'    (not reasonable for records, but we have objects! fields are not
           in object types)















Overloading


Already met in Haskell dealing with classes



Relevant notion in O.O.











class Rectangle {
    ...
    function contains(pt:Point): Boolean is
        { ... }
    function contains(x,y:Integer): Boolean is
        { ... }
}


treated by Java and C++ as different names

the language processor *statically* determines 
what method body is to be executed







var
    r: Rectangle;
    pt: Point;
    x, y: Integer;
function m(...): ... is {
    ... r  contains(pt) ... r contains(x,y) ...
}









(differences)
Overloaded and overridden methods 


                overloaded methods      overridden methods
              ----------------------------------------------- 
message sends | resolved statically  |  resolved at run time
              |                      |
which class?  | (tipically)  same    |    subclass                  
              |                      |
signature     |        different     |   same (or subtype)






interaction between 



overloaded method names    and     overridden methods names
   (static resolution)                (dynamic resolution)
                
                        can result in

                       GREAT CONFUSION








class C {
        ...

    function equals(other:CType): Boolean is
           { ... }         // equals 1
}



class SC inherits C modifies equals {
          ...

    function equals(other:CType): Boolean is
           { ... }         // equals 1
 
    function equals(other:SCType): Boolean is
           { ... } // equals 2
}







CType and SCType are the types of objects of C and SC 


Clearly 

          SCType  <:  CType



c and c' of type CType
sc of type SCType



c := new C;
sc := new SC;
c' := new SC;

c <= equals(c);
c <= equals(c');
c <= equals(sc);

c' <= equals(c);
c' <= equals(c');
c' <= equals(sc);

sc <= equals(c);
sc <= equals(c');
sc <= equals(sc);


Which equals method is actually executed as a
result of each of the sends?



*  All 3 message sends to c result in the execution of method equals 1 from
class C.

*  All 3 message sends to c' result in the execution of method equals 1 in
class SC.

*  The first two message sends to sc also result in the execution of method
equals 1 from class SC.

*  Only the last message send, sc <= equals(sc), results in the execution
of method equals 2 from class SC.
