Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
CLOS solutions to binary methods
Didier Verna
didier@lrde.epita.fr
http://www.lrde.epita.fr/˜didier
March 21 2007
1/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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:
problematic concept in traditional OO languages
type / class relationship in the context of inheritance
2/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Table of contents
1 Problem: types, classes, inheritance
C++ implementation attempts
Explanation
2 The case of Common Lisp
CLOS implementation
Corollary: method combinations
3 Enforcing the concept usage level
Introspection
Binary function class
4 Enforcing the concept implementation level
Misimplementations
Strong binary functions
3/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
The test case
Used throughout this presentation
The Point class UML hierarchy
equal (ColorPoint) : Boolean
color : String
x, y : Integer
equal (Point) : Boolean
Point
ColorPoint
5/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
C++ implementation attempt #1
Details omitted
The C++ Point class hierarchy
class P oint
{
i n t x , y ;
bool equal ( Poi n t& p )
{ retu rn x == p . x && y == p . y ; }
} ;
class C olo r Po i nt : public P oin t
{
std : : s t r i n g co l o r ;
bool equal ( Col o rP o int& cp )
{ retu rn co l o r == cp . c o l o r && P oin t : : equ al ( cp ) ; }
} ;
6/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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 " ) ;
std : : cou t << p1 . eq ual ( p2 ) << st d : : e ndl ;
/ / => True . #### Wrong !
}
ColorPoint::equal only overloads Point::equal
in the derived class
From the base class, only Point::equal is seen
What we want is to use the definition from the exact
class
7/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
C++ implementation attempt #2
Details omitted
The C++ Point class hierarchy
class P oin t
{
i n t x , y ;
v i r tu a l bool equal ( P o int& p )
{ retu rn x == p . x && y == p . y ; }
} ;
class C olo r Po i nt : public P oin t
{
std : : s t r i n g co l o r ;
v i r tu a l bool equal ( C o lor P oi n t& cp )
{ retu rn co l o r == cp . c o l o r && P oin t : : equ al ( cp ) ; }
} ;
8/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
But this doesn’t work either !
We still get overloading, still not what we want
The forbidden fruit
v i r tu a l bool equal ( Point& p ) ;
v i r tu a l bool equal ( ColorPoint& cp ) ; / / #### Forbidden !
Invariance required on virtual methods argument types
Worse: here, the virtual keyword is silently ignored
And we get an overloading behavior, as before
Why ? To preserve type safety
9/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Constraints for type safety
covar iance, contravariance. . . invariance
When subtyping a polymorphic method, we must
supertype the arguments (contravariance)
subtype the return value (covariance)
Note: Eiffel allows for arguments covariance
But this leads to possible run-time errors
Note: C++ is even more constrained
The argument types must be invariant
Implementing binary methods in traditional OO
languages is
either impossible directly
or possible but unsafe
11/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
CLOS: the Common Lisp Object System
A different object model
C++ methods vs. CLOS generic functions
C++ methods belong to classes
CLOS generic functions look like ordinary functions
(outside classes)
C++ single dispatch vs. CLOS multi-methods
C++ dispatch based on the first (hidden) argument type
(this)
CLOS dispatch based on the type of any number of
arguments
Note: a CLOS “method” is a specialized
implementation of a generic function
13/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
CLOS implementation
No detail omitted
The CLOS Point class hierarchy
( defclass po i n t ( )
( ( x : i n i t a r g : x : r eader point x )
( y : i n i t a r g : y : read er point y ) ) )
( defclass c o lor poi n t ( p o i n t )
( ( color : i n i t a r g : c o l o r : re ader p oin t co l o r ) ) )
( defgeneric p o i n t = ( a b ) )
( defmethod point = ( ( a p o i n t ) ( b p o i n t ) )
( and ( = ( po int x a ) ( po intx b ) )
(= ( po int y a ) ( po inty b ) ) ) )
( defmethod point = ( ( a co l o r p o int ) ( b c o l or p oin t ) )
( and ( s tr i ng = ( p o int col o r a ) ( p o i nt c ol o r b ) )
( call next method ) ) )
14/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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 ( make color point : x 1 : y 2 : c o l o r " red " ) )
( cp2 ( make color point : x 1 : y 2 : c o l o r " green " ) ) )
( values ( p o i n t = p1 p2 )
( p o i n t = cp1 cp2 ) ) )
; ; => ( T NIL )
Proper method selected based on both arguments
(multiple dispatch)
Function call syntax, more pleasant aesthetically
(p1.equal(p2) or p2.equal(p1) ?)
Hence the term binary function
15/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Applicable methods
There are ore 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
16/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Using the and method combination
Comes in handy for the equality concept
The and method combination
( defgeneric p o i n t = ( a b )
( : methodcombination an d )
)
( defmethod point = and ( ( a p o i n t ) (b point ) )
( and ( = ( po int x a ) ( po intx b ) )
(= ( po int y a ) ( po inty b ) ) ) )
( defmethod point = and ( ( a c o lo r poi n t ) ( b co l o r p o int ) )
( and ( call next method )
( s tr i ng = ( p o int col o r a ) ( p o int col o r b ) )
)
)
In CLOS, the generic dispatch is (re-)programmable
17/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Binary methods could be misused
Can we protect against it ?
The point= function used incorrectly
( l e t ( ( p ( make point : x 1 : y 2 ) )
( cp ( make color point : x 1 : y 2 : color " red " ) ) )
( p o i n t = p cp ) )
; ; => T #### Wrong !
(point= <point> <point>) is an applicable
method (because a color-point is a point)
The code above is valid
And the error goes unnoticed
19/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Introspection in CLOS
Inquiring the class of an object
Using the function class-of
( unless ( eq ( clas s of a ) ( cla ss of b ) )
( error " Obje cts n ot o f the same c las s . " ) )
When to perform the check ? (w/o code duplication)
In the basic method: neither efficient, nor elegant
In a before-method: not available with the and
method combination
In a user-defined method combination: not elegant
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?
20/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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 b i nar y fun c tio n ( st an da rd g en er ic f unction )
( )
( : metac lass f un cal la ble s tan dar d cla ss ) )
( defmacro d e f bin a r y ( functionname la mb da l ist &res t o pti o ns )
( defgeneric , function name , lam bd a li st
( : ge ne ric f uncti on clas s b ina r y fu n cti o n )
, @options ) )
21/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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
( defmethod camuc : before ( ( bf b ina r y f u n ct i o n ) c la ss es )
( ass ert ( equal ( car cl as se s ) ( ca dr classe s ) ) ) )
22/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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)
Is a generic function
Can be specialized
Specializing the add-method generic function
( defmethod addmethod : b ef or e ( ( b f b i nar y fu n c ti o n ) method )
( ass ert ( apply # equal ( m et hod s pe ciali ze rs method ) ) ) )
24/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Binary methods could be forgotten
Can we protect against it ?
Strong binary functions:
Every subclass of point should specialize point=
Late checking: at generic function call time
(preserve interactive development)
Binary completeness:
1 There is a specialization on the arguments’ exact class
2 There are specializations for all super-classes
Introspection:
Binary completeness of the list of applicable methods
c-a-m-u-c returns this !
Hooking the check
( defmethod camuc ( ( b f b i n ary fun c t io n ) cl as se s )
( mu lt ip le value bind ( methods ok ) ( call next method )
; ; . . .
( values methods ok ) ) )
25/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Is there a bottommost specialization ?
Check #1
classes = ’(<exact> <exact>)
method-specializers returns the arguments
classes from the defmethod call
We should compare <exact> with the specialization
of the first applicable method
Check #1
( l e t ( ( method ( car methods ) )
( c las s ( car ( me thod sp ecial iz ers method ) ) ) )
( ass ert ( equal ( l i s t c l as s c l ass ) classes ) )
; ; . . .
)
26/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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
( labels ( ( check binary completeness ( c las s )
( find method bf ( m eth od qu ali fi e rs method )
( l i s t cla s s c las s ) )
( d o l i s t
( cls ( remove if
# ( lambda ( e l t )
( eq e l t ( f ind cl a ss
s tandard o bject ) ) )
( class d ir ect s up er class es c l ass ) ) )
( check binary completeness c l s ) ) ) )
( check binary completeness cl a ss ) )
27/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
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
28/29
Binary
methods in
CLOS
Didier Verna
Introduction
Problem: C++
C++ attempts
Explanation
Solution: CL
CL OS solution
Method comb.
Usage
Introspection
Binary function class
Implementation
Misimplementations
Strong bin. functions
Conclusion
Quesλ ions ?
Logo by Manfred Spiller
29/29