University of Calgary
mail toRob Kremer

Object-Based Languages

Lecture Notes on

Abadi, M. & Cardelli, L. (1996). A Theory of Objects. New York, Springer.  Chapter 4: "Object-Based Languages."

CPSC 701.01 Object Theory


Table of Contents

Ojbect-based Languages
OO Languages need not be based on classes. 

Object may be thought of as a more primitive concept than class: 

  • Object-based languages may be just a powerful as class-based languages, and may even simulate classes

4.1 Objects without Class
Properties
Base object-based language properties: 
  • Do not have classes
  • Have constructs for individual objects
 
example

    ObjectType Cell is
      var
    contents: Integer;
      method get(): Integer;
      method
    set(n:Integer);
    end;
    object cell:Cell is
      var contents: Integer := 0;
      method get(): Integer is return self.contents end;
      method set(n: Integer) is self.contents := n end;
    end;
This creates a single object of  type Cell named cell. 
Simulating
the new 
operator

We can easily simulate the new operator for Cell so that it "feels" like a class: 
 
    procedure newCell(m: Integer): Cell is
      object cell: Cell is
        var contents: Integer := m;
        method get(): Integer is return self.contents end;
        method set(n: Integer) is self.contents := n end;
      end;
      return cell;
    end;
    var cellInstance: Cell := newCell(0);
Hence, the roll of new can be taken over by a procedure. 
Insight

Classes need not be assumed: objects are the more primitive notion. 


4.2 Prototypes and Clones
Prototype-based Languages
In prototype-based languages: 
  • stock objects (prototypes) are generated first 
    • they act like classes
    • but, prototypes are full-function objects
  • other objects are cloned from these 
    • these are like regular objects in a class-based language
    • e.g.:
    • var cellClone: Cell := clone cellInstance;
    • clone acts like new in class-based languages
  • other prototypes may be cloned and extended from the original prototype 
    • like subclasses in class-based languages
 
Extending

We need some way of customizing clones so they aren't identical to their prototypes 
Simplest is to customize field values: 
    cellClone.contents := 3;
But we want to customize the behaviour of objects by modifying their methods 

We need to dynamically modify their methods: 

    cellClone.get :=
      method(): Integer is
        if self.contents < 0 then return 0 else return self.contents end;
      end;
Now, cellCone will never return negative numbers. 

Method update is statically typeable. 
 

example

    ObjectType ReCell is
      var contents: Integer;
      method get(): Integer;
      method set(n: Integer);
      method retstore();
    end;
    object reCell: ReCell is
      var contents: Integer := 0;
      method get(): Integer is return self.contents end;
      method set(n: Integer) is
        let x = set.get();
        self.restore := method() is self.contents := x end;
        self.contents := n;
      end;
      method restore() is self.contents := 0 end;
    end
Note that there is no backup field. 

Why not? 
 


4.3 Inheritance by Embedding and by Delegation
Inheritance
Object cloning + method update + object extension = inheritance (sort of...) 
  • cloning is inheritance
  • method update is overriding
  • object extension is adding attributes to subclasses
 
Object Extension

Not so easy 
  • Object identity is usually associated with its address
  • How can you extent an object without changing its address if there is another object after its address+length?
Most languages don't allow unconstrained object extension. 
Obtaining
attributes
of donor
objects and
incorporating
 attributes

 Four* possible language types: 
 


Incorporating attributes


Embedding
Delegation
Obtaining
donor 
attributes*
Implicit
   
Explicit
   
*Actually, there are other possibilities other than implicit and explicit: some languages explicitly inherit attributes in groups or by sub-object groupings.  One of these strategies is mixin inheritance
Embedding vs
Delegation

Embedding and Delegation are just the same principles as we saw in class-based languages in section 2.1 (naive model) and section 2.3 (method lookup). 
  • Even the treatment of self is the same.
 


4.4 Embedding
Embedding
Model
Simplest model 
  • Every object is self-contained
 
Explicit Inheritance

We mush specify each element to be inherited: 
    object cell: Cell is
      var contents: Integer := 0;
      method get(): Integer is return self.contents end;
      method set(n: Integer) is self.contents := n end;
    end;
    object reCellExp: ReCell is
      var contents: Integer := cell.contents;
      var backup: Integer := 0;
      method get(): Integer is 
        return embed cell.get()
      end;
      method set(n: Integer) is
        self
    .backup := self.contents;
        embed cell.set(n);
      end;
      method restore() is self.contents := self.backup end;
    end;
 
embed

embed means to execute the method (cell.get() in this case) with the current object bound to the this reference (in this case to a reCellExp instead of cell). 
Shorthand

Instead of the rather verbose 
    method get(): Integer is return embed cell.get() end;
we can use 
    method get copied from cell;
but the embed construct is still needed (e.g. in the set() method). 
Implicit Inheritance

We can implicitly copy all the attributes down by specifying the donor object: 
    object cell: Cell is
      var contents: Integer := 0;
      method get(): Integer is 
        return self.contents
      end;
      method set(n: Integer) is
        self.contents := n
      end;
    end;
    object reCellImp: ReCell extends cell is
      var backup: Integer := 0;
      override set(n: Integer) is
        self
    .backup := self.contents;
        embed cell.set(n);
      end;
      method restore() is 
        self.contents := self.backup
      end;
    end;
  • This definition is very close to the class definition 
  • embed is still needed 
 
Another Alternative

 We could also just make a pure extension of cell followed by a method update: 
    object reCellImp1: ReCell extends cell is
      var backup: Integer := 0;
      method restore() is 
        self.contents := self.backup 
      end;
    end;
    reCellImp1.set :=
      method(n: Integer) is
        self.backup := self.contents;
        self.contents := n;
      end;
This can only work with embedding because the method update only affects the one object. 
  • If we tried the same thing with delegation, all object for which this is the donor ("subclasses") would be affected.
 


4.5 Delegation
Attributes are shared across objects. 
  • Objects are extended, but the inheritance is by redirecting the access to attributes by delegating (or referencing) to the prototype object.
  • Implicit delegation inheritance is the most common.
Model

The host (child object) designates another object as its donor (parent object). 
  • Host has a pointer (parent link) to its donor.
  • If an attribute is not found in the host, the parent link is followed and the donor is searched; if not found there, then the donor's parent link is followed ...
 
Delegation

    object cell: Cell is
      var contents: Integer := 0;
      method get(): Integer is 
        return self.contents
      end;
      method set(n: Integer) is
        self.contents := n
      end;
    end;
    object reCellImp: ReCell child of cell is
      var backup: Integer := 0;
      override set(n: Integer) is
        self
    .backup := self.contents;
        delegate cell.set(n);
      end;
      method restore() is 
        self.contents := self.backup
      end;
    end;
The inherited attributes in reCellImp  (get() and contents) are not copied into the host (as for embedding inheritance), but are referenced via the parent link 
  • All copies of reCellImp share the same get() and contents attributes.
 
delegate

 delegate means to execute the donor method with self bound to the host. 
  • delegate: obtain method from donor at time of invocation
  • embed: obtain method from donor at time of object creation
  •  
    Oops!

    Obviously, there is a problem with the example above: 
    • We probably do not mean to have every reCellImp containing the same value for the contents attribute!
    Fix this by overriding the contents attribute (remember, it's invariant!) 
      object reCellImp: ReCell child of cell is
        override contents: Integer := cell.contents;
        var backup: Integer := 0;
        override set(n: Integer) is
          self
      .backup := self.contents;
          delegate cell.set(n);
        end;
        method restore() is 
          self.contents := self.backup
        end;
      end;
     
    self  binding

     The above example couldn't work unless self was always bound to the host (and not the donor) 
    static type

    It is critical that the exact type of the donor be statically known at compile time. 
    • Otherwise, we might inherit something too specific and violate subsumption.
     
    Explicit
    Inheritance

    Individual methods (and possibly fields) are individually delegated. 

    No parent declarations. 

      object reCellExp is
        var contents: Integer := cell.contents;
        var backup: Integer := 0;
        method get(): Integer is
          return delegate cell.get()
        end;
        method set(n: Integer) is
          self
      .backup := self.contents;
          delegate cell.set(n);
        end;
        method restore() is 
          self.contents := self.backup
        end;
      end;
     
    Advantage

    Explicit delegation provides a clean way to handle multiple inheritance under conditions of ambiguous or conflicting inherited attributes: 
    • The programmer explicitly has to declare which one (or more) of the donor methods to use.
     


    4.6 Embedding versus Delegation
    Which is best is still an open issue
    Embedding
    Delegation
    Has copies of donor attributes. Has no copies of donor attributes, but accesses them through a parent link.
    Inherited attributes are identical to local attributes. Must perform attribute lookup through a chain of parent links to access inherited attributes.
    self binding isn't an issue. self binding must be carefully handled: donor (inherited) methods must be executed with self bound to the host (not donor) object.
    Changes to donor field values and method updates are not seen by inheriting hosts. Any changes to donor field field values and method updates are seen by the inheriting hosts.
    --
    Many languages allow replacement of donor links, which dynamically changes the behaviour of the host and all object for which is is a donor.
    Cloning is simple. Cloning copies the donor link, so all clones share the donor's mutable fields and methods.
    Less common. More common.
    Pervasive change is not easy. Pervasive change to all hosts of donor is easy.
    Objects are autonomous. Dynamic webs of object links can make for a fragile system.
    Space efficiency must be achieved though behind-the-scenes optimization. Space efficient because attributes are shared.
     


    4.7 Dynamic Inheritance and Mode-Switching
    Static Inheritance
    Static delegation inheritance is when parent links are fixed (constant). 
    Dynamic Inheritance

    Dynamic delegation inheritance is when parent links are allowed to be reassigned, which changes the behaviour of the host objects. 
    Dangerous Feature?

    Dynamic inheritance can be considered very dangerous: 
    • if we reassign the parent link to an unrelated delegate with a different interface, subsumption (and all assumptions to do with type) go out the window.
     
    Elegant Feature: Mode Switching

    But constrained or disciplined dynamic inheritance allows some very elegant and useful features. 
    • Mode-switching is changing the behaviour of an object with changes in state (this requirement arises often).
    • The interface of the donor objects are restricted to be identical.
    • e.g.: A window might react differently to various messages (such as paint()) when it is iconified, normal, hidden, or full-screen state.
    • Mode-switching can be implemented by just changing the parent link of the host object to a parent that implements the appropriate behaviour.
    • The static inheritance solution usually involves a state flag that is checked in as big case statement in every method.
      • not very elegant
      • error prone
      • implies pervasive code changes if a new state needs to be implemented.
     
    example

      reparent reCellImp to cell';
     
    Simulating Mode Switching

    Mode switching can be simulated without dynamic inheritance using method update: 
    reCellImp.get :=
      method(): Integer is
        return embed cell'.get()
      end;
    reCellimp.set :=
      method(n: Integer) is
        self.backup := self.contents;
        embed cell'.set(n);
      end;
     


    4.8 Traits: From Prototypes back to Classes?
    Traits
    A trait is an object that typically only contains methods. 
    Prototype

    A prototype is an object that typically  only contains fields and has a trait as a parent. 
    Normal Objects

    A normal object is an object that is cloned from a prototype and therefore shares its traits of its prototype. 
    Roles

    Traits, prototypes, normal objects are all objects.
    Traits, prototypes should never be used.
    Traits should never be cloned.
    Normal object only carry out state. 
    Violation of Prototyping!

    Argument: 
      Traits aren't really true objects because they aren't supposed to be cloned or used. 

      Prototypes aren't really true object because they aren't meant to be used. 

      The idea or prototyping is that everything is an ordinary object. 



      We are right back to the distinction that class-based languages make between objects and classes!
     
    Continuum

    The distinction between class-based and object-based languages should be thought of a continuum: 
     


    4.9 Types for Object-Based Languages
    Dynamic Features/
    Static Type Systems
    Dynamic features of object-based languages are difficult to capture with static type systems. 
     
    Typed
    Object-Based 
    Languages

     Appropriate type systems are just emerging: 
    • New typed object-based languages accomplish this by restricting the dynamic features
      • These type systems make the languages look like class-based systems.
     


    The University of Calgary
    back to previous page
    back
    Up to page above
    up


    mail toRob Kremer
    Last Modified Aug. 15, 2005
    CPSC 701.01 Object Theory
     Graduate Course in Software Engineering