




Any constraints necessary

on

arguments and result types

of

redefined methods


when

we wish only
 
 *type correctness to be preserved* ?







class C {

   function m(s:S): T is { .... }

   function n(anS:S): U is {
   ... self <= m(anS) ... }
}


class SC inherits C modifies m {

   function m(s:S): T is // For which S, T safe?
   { ... }
}

ansc <= n


in n's body:

self <= m(anS)

if we invoke n on an object of SC, 
the redefined m will be run

so  we need

S'-> T' <: S -> T       hence   S <: S'


Changing argument types (contravariantly)
seems useless in actual examples







Some powerful constructs 
build 
subclasses without subtypes










nonetheless

types of redefinded methods need to be subtypes















Changing instance variable types in subclasses

NOT possible!

Recall discussion on reference types.










There should be 
a covariant change if looked at as values (r-value)
a contravariant change if looked at as location (l-value)


class Rect {
   ul:Point := nil; // upper left corner
   lr:Point := nil; // lower right corner

   function setUL(newUL:Point): Void is
   { self.ul := newUL }
}


class ColorRect {
   ul:ColorPoint := nil;
   lr:ColorPoint := nil;
   ...
}


Subclass ColorRect redefines types of instance variables.

BUT setUL would assign a Point to a ColorPoint variable!!!










Java solution:

The new instance variable are actually 

      * new instance variables with the same name *







==============================







Onother sort of change in subclasses: methods' visibility






Showing hidden methods in subclasses is sound
w.r.t. the subtype rule for object types


The opposite NOT!!

















May we do the reverse? 
Yes, of course.
if we do not mind subclasses producing subtypes... (why?)














Look at the type of an object in a subclass
changing a method from public to protected.




public        (for all, public!)

protected     (just for objects in class and subclasses)

hidden        (just for object in class)







public --> protected         no problem


protected  --> private       no problem
                             beware when it is overridden 
                             in subsubclasses


All restrictions of visibility possible
... if we do not care about subtyping!












========================================================



                   Non Class-based
        Object Oriented Programming Languages

















Object-based languages




In most object-based languages, 
objects can be constructed directly by means of
appropriate used-define functions.



Example:


function makePoint(nx:Integer,ny:Integer): PointType is
{
   return object {
     x: Integer := nx;
     y: Integer := ny;

     function move(dx: Integer,dy:Integer): Void is
     { x := x + dx;
       y := y + dy;
     }
   }
}


makePoint produces objects all with the same shape.



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

       A special kind of object-based languages:

             Prototype-based languages



- Notion of "prototype"

- Use of cloning

- Updating features

- (Usually) dynamic updating also of methods



If everything is updatable, no distinction between
variables and methods (both called "term features")



Features can be "added" by

Extension 

o extends p   ===>  o has separate copies of p's fields



Delegation


o delegates to p  ===>  p's fields in o 
                        are still those of p


Thus an object created using delegation 
retains ties to its prototype parent,

while an object created by extension 
is independent of its parent.







Object-based advantages: simpler sintax, 
                         flexibility (dynamic updates!)


dynamic updates ===>  semantic complexity



Foundation for object-based languages: 
Object calculus [Abadi, Cardelli]




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

        Another kind of non class-based languages


                Multi-method Languages








No receivers of messages

Method calls like procedure calls

BUT method body to be executed depends on run-time types


function equal(p1:Point,p2:Point): Boolean is
 { return p1.x = p2.x & p1.y = p2.y }


function equal(p1:ColorPoint,p2:ColorPoint): Boolean is
 { return p1.x = p2.x & p1.y = p2.y
                      & p1.color = p2.color }








ColorPoint <: Point

pt1, pt2: Point 

If run-time type is Point, first equal

If run-time is Color-Point, second equal



- No receiver

- body selection made at run time (dynamic method overloading)

An overloding different from overloading in Java (static)



In example: what if equal(pt1, pt2) with

pt1 is Point and pt2 is ColorPoint at run-time?



A Point cannot be a ColorPoint, hence...



Chioce depending on the "better match",
for instance what pt1 and pt2 both are ColorPoint



Not always easy!

Example: 



function compare(p1:Point, p2: ColorPoint): Boolean is
  { return ... }

function compare(p1:ColorPoint, p2:Point): Boolean is
  { return ... }





compare(pt1, pt2) no type-safe when both Point



ambiguity when both ColorPoint


CLOS: rules provided to specify how to disambiguate

Cecil: 
programmer must provide other methods to get out of ambiguity
(similar to java for overloaded methods statically ambiguous)





Multi-methods: no problems with binary methods!!!



No meaning for "self"!


Problems about encapsulation and information hiding


Single-dispatch languages: 
         method lookup among methods of the receiver
        (those allowed to access non-public features) 





Multi-method languages: 
        all methods with the same name 
        logically belongs together (in terms of lookup strategy)




contains(aPoint, aCircle) 

may need non-public features of both Point and Circle





Which class does contains belong to?





Result: problems with modularity!!




multi-methods languages really Object-Oriented?














                   ==============================

                         Some O.O.languages




*Simula 67*

Extension of Algol 60

Notions of object, class, inheritance, 
dynamic method invocation

No information hiding (neither for instance variables, 
nor methods)






*Beta*



Successor of SImula 67



Beta and Simula: use of "inner" for method overriding


Invocation of everridden method:
code in superclass before inner
code of subclass
code in superclass after inner







Beta: use of virtual classes

Example (it uses Bruce's notation)



class Cell {
   deftype A <: Object;
   value: A := null;

   function set(v:A): Void is
   { value := v }

   function get(): A is
   { return value }
}

class StringCell inherits Cell {
   deftype A <: String;
   ...
}


'A' is not a type parameter!!!



Just to specify that it can be specialized in subclasses




StringCell "subtype" of Cell so...

type problems because of covariant change in set!

Run-time type checks added!





We could us polymorphic classes instead of Virtual types 

NOT always!!


ObjectType Observer {
   deftype S <: Subject;
   deftype E <: Event;

   function notify(s:S, e: E): Void;
}

ObjectType Subject {
   deftype O <: Observer;
   deftype E <: Event;

   function register(s:S): Void;

   function notifyObservers(e:E): Void;
}


class ObserverClass {
   deftype S <: Subject;
   deftype E <: Event;

   function notify(s:S, e: E): Void is
   { ... }
}

class SubjectClass {
   deftype O <: Observer;
   deftype E <: Event;
   observers:Array of O;

   function register(o:O): Void is
   { ... }
   function notifyObservers(e:E): Void is
   { ... observers[i].notify(self,e) ... }
}





ObjectType WindowObserver { ... }

ObjectType WindowSubject { ... }

class WindowObserverClass {
   deftype S <: WindowSubject;
   deftype E <: WindowEvent;

   function notify(s:S, e:E): Void is // override
   { super.notify(s,e); ... s.windowMeth() ... }
}

class WindowSubjectClass {
   deftype O <: WindowObserver;
   deftype E <: Event;

   function windowMeth(...): ... is // new method
   { ... }
}

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


* C++ and Java *



C++  both  O.O. and procedural

Java  only O.O.





C++ and Java  originally invariant

C++ now covatiant changes in return types



C++ multiple inheritance

Java single inheritance

but multiple for interfaces (hence object types)

C++ and Java: Subtyping determined by declaration



Java: not fully supporting subtyping

bexp?texp:fexp

type checking requires types texp and fexp to be the same or one
extends the other

bexp?pt:pt   OK

bexp?pt:cpt  OK

bexp?fpt:pt  OK

bexp?fpt:cpt  NO!!

fpt and cpt have an upper bound but not necessarily a least one

Fig.7.4



  *Smalltalk*

   dynamically typed


  *Eiffel*

 use of "like Current"  (good for binary methods)
        not sound w.r.t. static typing


Sather extended Eiffel fixing subtype problems 
(controvariant changes in patameter types; 
no changes in instance variables)








