Upload
ssaurabhss
View
214
Download
0
Embed Size (px)
DESCRIPTION
Oops A2z part2
Citation preview
CS152: Programming Languages
Lecture 24 Bounded Polymorphism; ClasslessOOP
Dan GrossmanSpring 2011
Revenge of Type Variables
Sorted lists in ML (partial):
type a slist
make : (a -> a -> int) -> a slist
cons : a slist -> a -> a slist
find : a slist -> a -> a option
Getting by with OO subtyping:
interface Cmp { Int f(Object,Object); }
class SList {
... some field definitions ...
constructor (Cmp x) {...}
Slist cons(Object x) {...}
Object find(Object x) {...}
}
Dan Grossman CS152 Spring 2011, Lecture 24 2
Wanting Type Variables
Will downcast (potential run-time exception) the arguments to fand the result of find
We are not enforcing list-element type-equality
OO-style subtyping is no replacement for parametricpolymorphism; we can have both:
interface Cmp { Int f(a,a); } // Cmp not a type
class SList { // SList not a type (SList e.g. is)
... some field definitions (can use type a) ...
constructor (Cmp x) {...}
Slist cons(a x) {...}
a find(a) {...}
}
Dan Grossman CS152 Spring 2011, Lecture 24 3
Same Old Story
I Interface and class declarations are parameterized; theyproduce types
I The constructor is polymorphicI For all T, given a Cmp, it makes a SList
I If o has type SList, its cons method:I Takes a TI Returns a SList
No more downcasts; the best of both worlds
Dan Grossman CS152 Spring 2011, Lecture 24 4
Complications
Interesting interaction with overloading and multimethods
class B {
unit f(C x) {...}
unit f(C x) {...}
}
class C { unit g(B x) { x.f(self); } }
For C where T is neither Int nor String, can have no match
I Cannot resolve static overloading at compile-time withoutcode duplication and no abstraction (C++)
I To resolve overloading or multimethods at run-time, needrun-time type information including the instantiation T (C#)
I Could disallow such overloading (Java)
I Or could just reject this sort of call as unresolvable (?)
Dan Grossman CS152 Spring 2011, Lecture 24 5
Wanting bounds
There are compelling reasons to bound the instantiation of typevariables
Simple example: Use at supertype without losing that its asubtype
interface I { unit print(); }
class Logger< a { // must apply to subtype of I
a item;
a get_it() { syslog(item.print()); item }
}
Without polymorphism or downcasting, client could only useget_it result for printing
Without bound or downcasting, Logger could not print
Issue isnt special to OOPDan Grossman CS152 Spring 2011, Lecture 24 6
Fancy Example from A Theory of Objects Abadi/Cardelli
With forethought and structural (non-named) subtyping, boundscan avoid some subtyping limitations
interface Omnivore { unit eat(Food); }
interface Herbivore { unit eat(Veg); } // Veg
Bounded Polymorphism
This bounded polymorphism is useful in any language withuniversal types and subtyping. Instead of . and .e, wehave < . and < .e:I Change to be a list of bounds ( < ) instead of a set of
type variables
I In e you can subsume from to
I e1[1] typechecks when 1 satisfies the bound in type of e1
One limitation: When is (1
Classless OOP
OOP gave us code-reuse via inheritance and extensibility vialate-binding
Can we throw out classes and still get OOP? Yes
Can it have a type system that prevents no match found andno best match errors? Yes, but we wont get there
This is mind-opening stuff if youve never seen it
Will make up syntax as we go...
Dan Grossman CS152 Spring 2011, Lecture 24 9
Make objects directly
Everything is an object. You can make objects directly:
let p = [
field x = 7;
field y = 9;
right_quad(){ x.gt(0) && y.gt(0) } // cf. 0.lte(y)
]
p now bound to an object
I Can invoke its methods and read/write its fields
No classes: Constructors are easy to encode
let make_pt = [
doit(x0,y0) { [ field x=x0; field y=y0;... ] }
]
Dan Grossman CS152 Spring 2011, Lecture 24 10
Inheritance and Override
Building objects from scratch wont get us late-binding and codereuse. Heres the trick:
I clone method produces a (shallow) copy of an object
I method slots can be mutable
let o1 = [ // still have late-binding
odd(x) {if x.eq(0) then false else self.even(x-1)}
even(x) {if x.eq(0) then true else self.odd(x-1) }
]
let o2 = o1.clone()
o2.even(x) := {(x.mod(2)).eq(0)}
Language doesnt grow: just methods and mutable slotsCan use for constructors too: clone and assign fields
Dan Grossman CS152 Spring 2011, Lecture 24 11
Extension
But that trick doesnt work to add slots to an object, a commonuse of subclassing
Having something like extend e1 (x=e2) that mutates e1 to havea new slot is problematic semantically (what if e1 has a slot namedx) and for efficiency (may not be room where e1 is allocated)
Instead, we can build a new object with a special parent slot:[parent=e1; x=e2]
parent is very special because definition of method-lookup (theissue in OO) depends on it (else this isnt inheritance)
Dan Grossman CS152 Spring 2011, Lecture 24 12
Method Lookup
To find the m method of o:
I Look for a slot named m
I If not found, look in object held in parent slot
But we still have late-binding: for method in parent slot, we stillhave self refer to the original o.
Two inequivalent ways to define parent=e1:
I Delegation: parent refers to result of e1
I Embedding: parent refers to result of e1.clone()
Mutation of result of e1 (or its parent or grandparent or ...)exposes the difference
I Well assume delegation
Dan Grossman CS152 Spring 2011, Lecture 24 13
Oh so flexible
Delegation is way more flexible (and simple!) (and dangerous!)than class-based OO: The object being delegated to is usually usedlike a class, but its slots may be mutable
I Assigning to a slot in a delegated object changes every objectthat delegates to it (transitively)
I Clever change-propagation but as dangerous as globals andarguably more subtle?
I Assigning to a parent slot is dynamic inheritance changes where slots are inherited from
Classes restrict what you can do and how you think, e.g., neverthinking of clever run-time modifications of inheritance
Dan Grossman CS152 Spring 2011, Lecture 24 14
Javascript: A Few Notes
I Javascript gives assignment extension semantics if field notalready there. Implementations use indirection (hashtables).
I parent is called prototypeI new F(...) creates a new object o, calls F with this bound
to o, and returns o.I No special notion of constructorI Functions are objects tooI This isnt quite prototype-based inheritance, but can code it
up:
function inheritFrom(o) {
function F() {}
F.prototype = o;
return new F();
}
I No clone (depending on version), but can copy fieldsexplicitly
Dan Grossman CS152 Spring 2011, Lecture 24 15
Rarely what you want
We have the essence of OOP in a tiny language with moreflexibility than we usually want
Avoid it via careful coding idioms:I Create trait/abstract objects: Just immutable methods
I Analogous role to virtual-method tables
I Extend with prototype/template objects: Add mutable fieldsbut dont mutate them
I Analogous role to classes
I Clone prototypes to create concrete/normal objectsI Analogous role to objects (clone is constructor)
Traits can extend other traits and prototypes other prototypes
I Analogous to subclassing
Dan Grossman CS152 Spring 2011, Lecture 24 16
Coming full circle
This idiom is so important, its worth having a type system thatenforces it
For example, a template object cannot have its members accessed(except clone)
We end up getting close to classes, but from first principles andstill allowing the full flexibility when you want it
Dan Grossman CS152 Spring 2011, Lecture 24 17