        

 


                             TYPE PROBLEMS 
                                  IN
                       OBJECT-ORIENTED LANGUAGES







Several deficiencies present in type systems of 

current O.O. languages



Many languages arose as object-oriented
extensions of imperative programming languages. 




In their type systems the programmer has little flexibility
in redefining methods in subclasses.










INVARIANT type systems:

types of methods and instance variables
in subclasses to be identical to those in superclasses











Invariant type systems enable

subclasses to have subtypes w.r.t. to the superclass


BUT...









                --------------------

         Invariant type system give problems 
              also for what concerns
                  Return Types



Some examples of problems



clone




clone is a method of the class Object

return type of clone?  ObjectType!!

So, in order to invoke a method on a clone?

Cast!  (which is unsafe...)













Example with deepClone 
(to clone objects present as instance variables)











class C {
   ...

   function deepClone(): CType is
   { self  clone(); ... }
}


class SC inherits C modifies deepClone {
   newVar: newObjType := nil;

   function newMeth(): Void is
   { ... }

   function setNewVar(newVarVal:newObjType): Void is
   { self.newVar := newVarVal }

   function deepClone(): SCType is
                   // illegal return type change!
                   // Must return CType instead
   var     // local variable declaration
      newClone:SCType := nil;
   {
      newClone := super<= deepClone();
                   // (*) another problem
      newClone <= setNewVar(newVar<= deepClone());
      return newClone
}
}



No possibility to write

               (anSC <= deepClone()) <= newMeth()






cast needed!!


Object Pascal and C++ :  the type cast is unchecked.



Java:  checked at run time. 





Modula-3:  use of  typecase statement 
           (i.e. a run-time check)











Giving a new name to deepClone:  SCdeepClone



NO USE!













Other inherited method could use deepClone
(and hence the C one)


In Java the problem arises for any clone method

clone has Object as return type....















In C++ return types can be specialized!!

Good news?

Problems still present

See (*) in Example








      newClone := super<= deepClone();
                        ^
                        |
                  it returns CType....







Covariant changes useful!!
But they should be made automatically.









                --------------------

         Invariant type system give problems 
              also for what concerns
                  Argument Types


Example: binary methods














class C {
   ...
   function equals(other:CType): Boolean is
   { ... }
   ...
}



class SC inherits C modifies equals {
   ...
   function equals(other:CType): Boolean is
                 // Want parameter type to be SCType instead!
   { super  <=  equals(other);
       ... // Cant access SC-only features in other
   }
   ...
}



Changing the name is no use
(can be used in other methods)



neither Overloading it 
(as above, because of the mechanism of 
 static method selection)









A trick, but dangerous:


class SC inherits C modifies equals {
   ...
   function equals(other:CType): Boolean is
   var
     otherSC:SCType := nil;
   { otherSC := (SCType)other; // type cast!
     ...
     return super<= equals(other) & ... }
   ...
}



Onother example



NodeType = ObjectType {
   getValue: Void -> Integer;
   setValue: Integer -> Void;
   getNext: Void -> NodeType;
   setNext: NodeType -> Void
}


class Node {
   value: Integer := 0;
   next: NodeType := nil;

   function getValue(): Integer is
   { return self.value }

   function setValue(newValue:Integer): Void is
   { self.value := newValue }

   function getNext(): NodeType is
   { return self.next }
   function setNext(newNext:NodeType): Void is
   { self.next := newNext }
}


A legal subclass (according to invariance restriction)


LglDbleNodeType = ObjectType {
   getValue:Void -> Integer;
   setValue:Integer -> Void;
   getNext:Void -> NodeType;
   setNext:NodeType -> Void;
   getPrev:Void -> LglDbleNodeType;
   setPrev:LglDbleNodeType -> Void
}


class LglDbleNode inherits Node modifies setNext {
   previous:LglDbleNodeType := nil;

   function getPrev(): LglDbleNodeType is
   { return self.previous }

   function setPrev(newPrev:LglDbleNodeType): Void is
   { self.previous := newPrev }

   function setNext(newNext:NodeType): Void is
   { super <= setNext(newNext);
     ((LglDbleNodeType)newNext) <= setPrev(self) }
                           // cast necessary to recognize setPrev!!!
}

Cast necessary in definition!


and also in use!!


during execution:

               dn <= setNext(o)      if o Node but not DbleNode

statically:

            (dn <= getNext()) <= getPrev()
                 ^
                 |    
           the type is NodeType

        




The hearth of the problem:

we need covariant changes also in argument types
when define
DbleNode class  as subclass of   Node class



but 

we must forget about

              DbleNodeType <: NodeType  !!!!!!!






Rules for <:  (see record types) prevents it !!!!!!!!!


 { ... setPrev:DblNodeType -> Void ...} 

                <: 

 { ... setPrev:NodeType -> Void ...} 



we should have NodeType <: DblNodeType  !!!!!!!!!!!!!!!!!!







An example: a completely new class

IndDoubleNodeType = ObjectType {
   getValue: Void -> Integer;
   setValue: Integer -> Void;
   getNext: Void -> IndDoubleNodeType;
   setNext: IndDoubleNodeType -> Void;
   getPrev: Void -> IndDoubleNodeType;
   setPrev: IndDoubleNodeType -> Void
}


function breakit(node:NodeType): Void is
{ node <= setNext(new Node) }


var
   n: NodeType
   dn: IndDoubleNodeType
{
   n := new Node;
   dn := new IndDoubleNode;
   breakit(n); // No problem
   breakit(dn) // Run-time error here!
}


IMPOSSIBLE TO HAVE IndDoubleNodeType <: NodeType


INVARIANT type systems:  
subclasses generates subtypes (good!)

BUT

many problems (to be solved with casts!!)


Well behaved subclasses 
with covariant changes in return and argument types

but subclasses are no more subtypes!!!!!!













