CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Binary Methods Programming:
the CLOS Perspective
Didier Verna
didier@lrde.epita.fr
http://www.lrde.epita.fr/˜didier
May 23 – ELS 2008
1/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Introduction
What are binary methods?
Binary Operation: 2 arguments of the same type
Examples: arithmetic / ordering relations (=, +, > etc.)
OO Programming: 2 objects of the same class
Benefit from polymorphism etc.
Hence the term binary method
However: [Bruce et al., 1995]
problematic concept in traditional OO languages
type / class relationship in the context of inheritance
2/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Table of contents
1 Binary Methods non-issues
Types, Classes, Inheritance
Corollary: method combinations
2 Enforcing the concept – usage level
Introspection
Binary function class
3 Enforcing the concept – implementation level
Misimplementations
Binary Completeness
3/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Types, Classes, Inheritance
The context
The Point class hierarchy
equal (ColorPoint) : Boolean
color : String
x, y : Integer
equal (Point) : Boolean
Point
ColorPoint
5/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
C++ implementation attempt #1
Details omitted
The C++ Point class hierarchy
class P o in t
{
i n t x , y ;
bool equal ( Po in t& p )
{ ret urn x == p . x && y == p . y ; }
} ;
class C ol o r P o i nt : p ubl i c P oi nt
{
st d : : s t r i n g co l or ;
bool equal ( Co lo rP oi nt& cp )
{ ret urn c o l or == cp . c ol o r && P o in t : : eq ual ( cp ) ; }
} ;
6/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
But this doesn’t work. . .
Overloading is not what we want
Looking through base class references
i n t main ( i n t argc , char argv [ ] )
{
Point& p1 = new ColorPoint ( 1 , 2 , " red " ) ;
Point& p2 = new ColorPoint ( 1 , 2 , " green " ) ;
st d : : c out << p1 . equal ( p2 ) << st d : : en dl ;
/ / => True . #### Wrong !
}
ColorPoint::equal only overloads Point::equal
From the base class, only Point::equal is seen
We want the definition from the exact class
7/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
C++ implementation attempt #2
Details still omitted
The C++ Point class hierarchy
class P o in t
{
i n t x , y ;
v i r t u a l bool eq u al ( Po in t& p)
{ ret urn x == p . x && y == p . y ; }
} ;
class C ol o r P o i nt : p ubl i c P oi nt
{
st d : : s t r i n g co l or ;
v i r t u a l bool eq u al ( C o lo rP oi nt& cp )
{ ret urn c o l or == cp . c ol o r && P o in t : : eq ual ( cp ) ; }
} ;
8/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
But this doesn’t work either. . .
Still got overloading, still not what we want
The forbidden fruit
v i r t u a l bool eq u al ( Point& p ) ;
v i r t u a l bool eq u al ( ColorPoint& cp ) ; / / #### Forbidden !
Invariance required on virtual methods argument types
Worse: virtual keyword silently ignored
(overloading behavior, just as before)
Why? To preserve static type safety
9/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Why the typing would be unsafe
And lead to errors at run-time
Example of run-time typing error
{
return p1.equal (p2);
}
bool foo (Point& p1, Point& p2)
But gets only a Point !The ColorPoint implementation
expects a ColorPoint argument
(ex. accesses the color field)
In fact, a ColorPoint Just a Point
10/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Constraints for type safety
When subtyping a polymorphic method
The covariance / contravariance rule
supertype the arguments (contravariance)
subtype the return value (covariance)
Note: C++ is even more constrained
The argument types must be invariant
Note: Eiffel allows for arguments covariance
But this leads to possible run-time errors
Analysis: [Castagna, 1995].
Lack of expressiveness
subtyping (by subclassing) = specialization
Object model defect
single dispatch (not the record-based model)
11/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
CLOS: the Common Lisp Object System
A different model
Class methods vs. Generic functions
C++ methods belong to classes
CLOS generic functions look like ordinary functions
(outside classes)
Single dispatch vs. Multi-methods
C++ dispatch: the first (hidden) argument’s type (this)
CLOS dispatch: the type of any number of arguments
12/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
CLOS implementation
No detail omitted
The CLOS Point class hierarchy
( defclass p oi n t ( )
( ( x : i n i t a r g : x : rea der p oi n t x )
( y : i n i t a r g : y : read er po i nt y ) ) )
( defclass co lo r po in t ( p o i nt )
( ( c o l or : i n i t a r g : c ol o r : reader p o in t co lo r ) ) )
; ; o p t io n a l
( defgeneric p o in t = ( a b ) )
( defmet hod p o i nt = ( ( a po i n t ) ( b p o i nt ) )
( and (= ( poin t x a ) ( pointx b ) )
(= ( point y a ) ( p oi nt y b ) ) ) )
( defmet hod p o i nt = ( ( a co l o r po in t ) ( b co lo r po in t ) )
( and ( st ri ng = ( p o i nt c ol or a ) ( p oi nt c ol or b ) )
( callnextmethod ) ) )
13/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
How to use it?
Just like ordinary function calls
Using the generic function
( l e t ( ( p1 ( makepoint : x 1 : y 2 ))
( p2 ( makepoint : x 1 : y 2) )
( cp1 ( makecolorpoint : x 1 : y 2 : c o lo r " red " ) )
( cp2 ( makecolorpoint : x 1 : y 2 : c o lo r " green " ) ) )
( values ( p o i nt = p1 p2 )
( p oi n t = cp1 cp2 ) ) )
; ; => ( T NIL )
Method selection: both arguments
(multiple dispatch)
Function call syntax: more pleasant aesthetically
(p1.equal(p2) or p2.equal(p1)?)
Hence the term binary function
14/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Applicable methods
There are more than one. . .
To avoid code duplication:
C++: Point::equal()
CLOS: (call-next-method)
Applicable methods:
All methods compatible with the arguments classes
Sorted by (decreasing) specificity order
call-next-method calls the next most specific
applicable method
Method combinations:
Ways of calling several (all) applicable methods
(not just the most specific one)
Predefined method combinations: and, or, progn etc.
User definable
15/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Using the and method combination
Comes in handy for the equality concept
The and method combination
( defgeneric p o in t = ( a b )
( : methodcombination and )
)
( defmet hod p o i nt = and ( ( a p oi n t ) ( b p o i n t ) )
( and (= ( poin t x a ) ( pointx b ) )
(= ( point y a ) ( p oi nt y b ) ) ) )
( defmet hod p o i nt = and ( ( a co lo r po in t ) ( b c ol or p oi nt ) )
( and ( callnextmethod )
( str in g= ( po in t co l or a ) ( po in t c o l or b ) )
)
)
In CLOS, the generic dispatch is (re-)programmable
19/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Anatomy of a method
A bit of vocabulary
defmethod point= and ((a point) (b point))
Method qualifiers Method specializers
20/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Binary methods could be misused
Can we protect against it?
The point= function used incorrectly
( l e t ( ( p ( makepoint : x 1 : y 2) )
( cp ( makecolorpoint : x 1 : y 2 : c o lo r " red " ) ) )
( p oi n t = p cp ) )
; ; => T #### Wrong !
(point= <point> <point>) is applicable
(a color-point is a point)
The code above is valid
The error goes unnoticed
22/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Introspection in CLOS
Inquiring the class of an object
Using the function class-of
( assert ( eq ( cl assof a ) ( cl assof b ) ) )
When to perform the check?
In all methods: code duplication
In the basic method: not efficient
In a before-method: not available with the and
method combination
In a user-defined method combination: not the place
Where to perform the check? (a better question)
Nowhere near the code for point=
Part of the binary function concept, not point=
We should implement the binary function concept
A specialized class of generic function?
23/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
The CLOS Meta-Object Protocol
aka the CLOS MOP
CLOS itself is object-oriented
The CLOS MOP: a de facto implementation standard
The CLOS components (classes etc.) are
(meta-)objects of some (meta-)classes
Generic functions are meta-objects of the
standard-generic-function meta-class
We can subclass standard-generic-function
The binary-function meta-class
( defclass bi na ry f u nc ti on ( sta ndar dge neri cf unct ion )
( )
( : met a c l ass fu nc all ab l e sta nd ard c las s ) )
( defmacro d e fb in a ry ( functionname lam bda li st &r e st o pt io ns )
( defgeneric , functionname , lam bda li st
( : ge ner ic fu nct ion cl as s bi na ry fu nc ti on )
, @options ) )
24/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Back to introspection
Hooking the check
Calling a generic function involves:
Computing the list of applicable methods
Sorting and combining them
Calling the resulting effective method
compute-applicable-methods-using-classes
Does as its name suggests
Based on the classes of the arguments
A good place to hook
We can specialize it!
It is a generic function . . .
Specializing the c-a-m-u-c generic function
( defmet hod camuc : b efo r e ( ( b f b in ar y fu n ct io n ) c las ses )
( assert ( eq ( ca r c las ses ) ( cadr cla sse s ) ) ) )
25/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Binary methods could be misimplemented
Can we protect against it?
We protected against calling
(point= <point> <color-point>)
Can we protect against implementing it?
add-method
Registers a new method (created with defmethod)
We can specialize it!
It is a generic function . . .
Specializing the add-method generic function
( defmet hod addmethod : b efor e ( ( b f b i n ar y fu nc t io n ) method )
( assert ( apply # eq ( metho dspe cial i zers method ) ) ) )
27/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Binary methods could be forgotten
Can we protect against it?
Every subclass of point should specialize point=
Late checking: at generic function call time
(preserve interactive development)
Binary completeness check:
1 There is a specialization on the arguments’ exact class
2 There are specializations for all super-classes
Hooking the check: c-a-m-u-c still the best candidate
( defmet hod camuc ( ( b f b i n ar y fu n c t io n ) c las ses )
( m u lti ple valu ebi nd ( methods ok ) ( callnextmethod )
; ; . . .
( values methods ok ) ) )
28/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Is there a bottommost specialization?
Check #1
classes = ’(<exact> <exact>)
methods = ’(appmeth1 appmeth2 ...)
We should compare <exact> with the specializers
of appmeth1
method-specializers does as its name suggest
Check #1
( l e t ( ( method ( car methods ) )
( cl as s ( ca r ( meth ods pecia lizer s method ) ) ) )
( assert ( eq cl as s ( car cla sses ) ) )
; ; . . .
)
29/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Are there specializations for all super-classes?
Check #2
find-method retrieves a generic function’s method
given a set of qualifiers / specializers
method-qualifiers does as its name suggests
class-direct-superclasses as well
Check #2
( l abe ls ( ( checkbinarycompleteness ( cl as s )
( findmethod bf ( me th o d qu ali fi ers method )
( l i s t cl as s cl as s ) )
( d ol i st
( c l s ( removeif
# ’ ( lambda ( e l t )
( eq e l t ( fi nd c la ss
st andar dob ject ) ) )
( c las sd ire ct sup erc las ses c la ss ) ) )
( checkbinarycompleteness cl s ) ) ) )
( checkbinarycompleteness c la ss ) )
32/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Conclusion
Binary methods problematic in traditional OOP
Multi-methods as in CLOS remove the problem
CLOS and the CLOS MOP let you support the concept:
make it available
ensure a correct usage
ensure a correct implementation
But the concept is implemented explicitly
CLOS is not just an object system
CLOS is not even just a customizable object system
CLOS is an object system designed to let you program
new object systems
35/36
CLOS Binary
Methods
Didier Verna
Introduction
Non-issues
Types, Classes,
Inheritance
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Bin Completeness
Conclusion
Articles
Bruce, K. B., Cardelli, L., Castagna, G., Eifrig, J., Smith, S. F.,
Trifonov, V., Leavens, G. T., and Pierce, B. C. (1995).
On binary methods.
Theory and Practice of Object Systems, 1(3):221–242.
Castagna, G. (1995).
Covariance and contravariance: conflict without a cause.
ACM Transactions on Programming Languages and
Systems, 17(3):431–447.
36/36