Comparison of various OO languages relatively to their late-binding
semantics
by Antoine Beugnard
Abstract.
We observe the various interpretations of overriding and overloading in
object oriented languages. With the description of an intend, represented as the
following UML diagram, we have "naively" implemented in 15 different
languages the same piece of code... and obtenained 11 different results.
The question is: How will this model
behave?
A new language signature with Perfect.
New tables for .NET
language interoperability ! Tables A,
B and C.
Not so simple !
Java changed its semantics from 1.3 to 1.4!!! Signature slot
(6,2) changed adopting the Visual
Basic
signature!
You'll find source of experiment for each language. You are invited
to re-do experiments with you own context and compilers. In our
experience (for Java and Scala), the semantics of language may
evolve... and we are interested in taking track of that. Thanks for you
help.
Outline
1. The test procedure for a
single
language...
2. The test procedures for
languages
interaction...
Results are presented in a table 3x6 for all possible
calls.
Note that only single late-binding is evaluated, and not
multiple
late-binding, even if some languages enable it (CLOS, Dylan). Results
reading help
is here.
3. Four proposals for a unified late-binding semantics : A pragmatic,
a reasonable (and a non-incremental
variant), a strict one and the
dont-surprise-the-programner
semantics.
4. Tested languages : Ada95, C++,
C#, CLOS, Dylan, Eiffel, Java (1.3 and 1.4 are different), nice,
OCaml, Perfect, Python, Scala (1.1 and 2.0
are different), Ruby, Smalltalk,
Strongtalk, Visual
Basic (To be tested...Beta, and others if you want to contribute).
and tested language interaction using 2 .NET languages: VisualBasic/C++,
VisualBasic/C#, C++/VisualBasic, C++/C#, C#/VisualBasic,
C#/C++
5. Comparisons for receivers Up u = new Up, Down
d = new Down, Up ud = new Down
6. Tested language interaction using 3 .NET languages: C#
client, VisualBasic client, C++
client.
-- Tested language interaction using CORBA (to be done)
7. Code transformation in order to simulate
the reasonable
semantics in Eiffel, Java
and C++
8. Conclusion and future work (PhD,
thèses)
and discussion...
Some related works : Overloading and
Inheritance
1. The programme for testing a single
language
late-binding semantics
5 classes are needed. 3 for parameters types (all code in a pseudo
language):
class Top end class
class Middle extends Top end class
class Bottom extends Middle end class
2 for the method redefinition tests. cv for covariant redefinition,
inv for invariant redifinition and ctv for contravariant one:
class Up
method cv(Top t) print "Up" end method
method inv(Middle) print "Up" end
method
method ctv(Bottom b) print "Up" end
method
end class
class Down extends Up
method cv(Middle m) print "Down" end
method
method inv(Middle) print "Down" end
method
method ctv(Midle m) print "Down" end
method
end class
A main program instantiates objets and makes all possible calls:
procedure main()
Up u = new Up
Down d = new Down
Up ud = new Down
| -- first column |
-- second column |
-- third column |
| u.cv(new Top) |
d.cv(new Top) |
ud.cv(new Top) |
| u.cv(new Middle) |
d.cv(new Middle) |
ud.cv(new Middle) |
| u.cv(new Bottom) |
d.cv(new Bottom) |
ud.cv(new Bottom) |
| u.inv(new Top) |
d.inv(new Top) |
ud.inv(new Top) |
| u.inv(new Middle) |
d.inv(new Middle) |
ud.inv(new Middle) |
| u.inv(new Bottom) |
d.inv(new Bottom) |
ud.inv(new Bottom) |
| u.ctv(new Top) |
d.ctv(new Top) |
ud.ctv(new Top) |
| u.ctv(new Middle) |
d.ctv(new Middle) |
ud.ctv(new Middle) |
| u.ctv(new Bottom) |
d.ctv(new Bottom) |
ud.ctv(new Bottom) |
end procedure
So what is behavior of this code ?
For sake of brevity we have suppressed the simple invariant case -
inv(Middle)
defined in Up and Down - since all languages behave identically.
However,
some tables include inv lines for compaison purpose. Results are
presented
in a table 3x6 for all possible calls. Note that only single
late-binding
is evaluated, and not multiple late-binding, even if some languages
enable
it (CLOS, Dylan). Results reading
help is here.
2. The programme for testing
languages interaction
late-binding semantics
5 classes are needed. 3 for parameters types (all code in a FIRST
pseudo
language):
class Top end class
class Middle extends Top end class
class Bottom extends Middle end class
1 for the methods definition (in the FIRST pseudo language):
class Up
method cv(Top t) print "Up" end method
method inv(Middle) print "Up" end
method
method ctv(Bottom b) print "Up" end
method
end class
1 for the method redefinition tests. cv for covariant and ctv for
contravariant
redifinition (in the SECOND pseudo language):
import Up,
Top, Middle, Bottom
class Down
extends Up
method
cv(Middle
m) print "Down" end method
method
inv(Middle)
print "Down" end method
method
ctv(Midle
m) print "Down" end method
end class
A main program (in a THIRD pseudo language) instantiates objets and
makes all possible calls (in the FIRST pseudo language or SECOND pseudo
language):
procedure
main()
Up u =
new Up
Down d
= new Down
Up ud
= new Down
| -- first column |
-- second column |
-- third column |
| u.cv(new
Top) |
d.cv(new
Top) |
ud.cv(new
Top) |
| u.cv(new
Middle) |
d.cv(new
Middle) |
ud.cv(new
Middle) |
| u.cv(new
Bottom) |
d.cv(new
Bottom) |
ud.cv(new
Bottom) |
| u.ctv(new
Top) |
d.ctv(new
Top) |
ud.ctv(new
Top) |
| u.ctv(new
Middle) |
d.ctv(new
Middle) |
ud.ctv(new
Middle) |
| u.ctv(new
Bottom) |
d.ctv(new
Bottom) |
ud.ctv(new
Bottom) |
end
procedure
3. Possible Unified Semantics
We have included inv(Middle) calls in order to show the discontinuity
that
appears in the thrird column when an invariant semantics is chosen
(C++,
C#, Java,...)
Here are rationale of these semantics...(comming soon)
Table 1 : Reasonable semantics
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Down |
| inv(Top) |
Compilation error |
Compilation error |
Compilation error |
| inv(Middle) |
Up |
Down |
Down |
| inv(Bottom) |
Up |
Down |
Down |
Note : Almost never implemented ! The most specialized method selected,
covariant and contravariant redefinition possible. Slot (5,3) for
incremental
compilation. The third columns is continuous...
Table 1 bis : Non incremental
Reasonable
semantics
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
| inv(Top) |
Compilation error |
Compilation error |
Compilation error |
| inv(Middle) |
Up |
Down |
Down |
| inv(Bottom) |
Up |
Down |
Down |
Note : Almost implemented by CLOS and Dylan.
The most specialized method selected, covariant and contravariant
redefinition
possible. Slot (5,3) prevents incremental compilation. The third
columns
is still continuous...
Table 2 : Pragmatic semantics
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Up |
| inv(Top) |
Compilation error |
Compilation error |
Compilation error |
| inv(Middle) |
Up |
Down |
Down |
| inv(Bottom) |
Up |
Down |
Down |
Note : Invariant semantics. Covariant and contravariant forbiden. This
is C# choice is close to Java
and
C++
one. The third column HAS A DISCONTINUITY
Table 2bis : Strict semantics
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Down |
Down |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Down |
| inv(Top) |
Compilation error |
Compilation error |
Compilation error |
| inv(Middle) |
Up |
Down |
Down |
| inv(Bottom) |
Up |
Down |
Down |
Note : Redefinitions with different type of argument is forbiden.
Down::cv(Middle)
and ctv(Middle) cannot be defined but Down::cv(Top) and
Down::ctv(Bottom)
can.
Slots (1,2) and (1,3) are yellow since cv cannot be specialized in
cv(Middle) but do not generate runtime errors since cv(Top) exists in
Down.
Covariant redefinitions are forbiden as contravariant ones, the latter
generate compilation errors: blue slot(5,3).
Table 2ter :
Dont-surprise-the-programner semantics
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
| inv(Top) |
Compilation error |
Compilation error |
Compilation error |
| inv(Middle) |
Up |
Down |
Down |
| inv(Bottom) |
Up |
Down |
Down |
Note : Suggested bu Howard Lovatt. Columns 2, d, and 3, ud, should be
the same since the object in question is a d. Row 5, ctv(m), column 3,
ud, should be E, since most programmers wouldn't expect to have to
re-compile super classes when deriving. Contravariance is forbiden.
My favorites are :
winner : Table 1; allows consitent covariant and
contravariant redefinitions and incremental compilers. Homogeneous
behavior.
outsider : Table 2bis : Simple. Homegenous behavior
but misses advantages of Table 1.
outsider : Table 2 : Close to popular OO languages.
Simple incremental modification to compilers of Java and C++ to apply
it.
But heterogeneous...
Color interpretation
- red : runtime error
- orange : potential runtime error
- yellow : correct but different
from
the reasonable
semantics (not the most specialized)
- blue : over-constrained (no
solution
found
while one exists)
4. Languages semantics
Table 3 : Ada 95
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Compilation error |
Down |
Compilation error |
| cv(Bottom) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Note : A lot of over-constraints that may be explain by the phrase
(Ada95
Ref. Manual) "No complicated method lookup is involved" 3.9(1e) but the
constraints seem be the result of a non-use of argument type
conformance.
See code and result.
Table 4 : C++, Scala 1.1
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Compilation error |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Up |
Note : Invariant semantics (ud shows that no covariant or
contravariant
is taken into account); slot (1,2) is over-constrained. See code
and results for C++.
See code
and results for Scala.
Table 5 : C#
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Up |
Note : Invariant semantics (ud shows that no covariant or
contravariant
is taken into account). This is the pragmatic
semantics. See code and results.
Table 6 : CLOS and Dylan
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Runtime error |
Runtime error |
Runtime error |
| ctv(Middle) |
Runtime error |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
Note : Close to reasonable semantics,
accepts
typing runtime risks. For CLOS, see code and
results.
For Dylan, see code and results.
Table 7 : Eiffel
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Compilation error |
Down |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Note : Covariant semantics, contravariance forbiden (lines 4, 5 and
6); slot (1,3) is runtime error prone. See code
and
results.
A recent proposal from B. meyer to remove the slot (1,3) problem is
discussed here : CATcalls.
A possible
code transformation to make Eiffel match the "reasonable
sematics".
Table 8 : Java before 1.3 and Scala 2.0
(and probably before)
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Compilation error |
Up |
Note : Invariant semantics (ud shows that no covariant or
contravariant
is taken into account); slot (6,2) is over-constrained. See code
and results (java 1.3). See code and
results (scala 2.0).
Table 8 bis : Java after 1.4
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Note : Invariant semantics (ud shows that no covariant or
contravariant
is taken into account); slot (6,2) could be more specialized (as Visual
Basic). See code
and results.
Table 9 : nice (naive translation)
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Compilation error |
Up |
Note : This is the result of a naive translation. a ctv(Middle) is
specified
in Down. Multiple late-binding, but contravariance not allowed. See code
and results.
Another translation, more in the spirit of nice, but less naive gives
results of table 9bis. See code and result.
Table 9bis : nice
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Down |
Table 10 : OCaml
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Down |
Down |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Up |
Down |
Down |
| ctv(Middle) |
Up |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
Note : In spite of appearances, no runtime errors could occur since
OCaml compiler detects type problems when they exist ! See code
and results.
I know that Top, Middle and Bottom classes are equivalent in OCaml
sense. Hence, this test may appear unfair. In a sense its true. But why
couldn't a programmer or a designer decide to have many classes with
exactly the same interface but with different method implentation?
There is some "semantics" in the name!
Table 10.5 : Perfect
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Error |
Error |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Error |
Error |
Error |
| ctv(Middle) |
Error |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
I did not make the test myself.The table is extracted from page 10 of the
technical repport NUIM-CS-TR-2005-07, Software Specification, Implementation and Execution with Perfect
by Gareth Carter and Rosemary Monahan. As far as I know, it is the
first time, the "language signature" is used during the design of a
language! Not as a decision tool to choose the semantics, but as a
kind of test.
Table 11 : Smalltalk, Python or Ruby
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Down |
Down |
| cv(Middle) |
Up |
Down |
Down |
| cv(Bottom) |
Up |
Down |
Down |
| ctv(Top) |
Up |
Down |
Down |
| ctv(Middle) |
Up |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
Note : Smalltalk is not typed, so many runtime errors could occur !
But there is a very good regularity. See Smalltalk code
and results.See Python code and results.
See Ruby code and results.
Table 12 : Strongtalk
|
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Up |
Up |
| cv(Bottom) |
Up |
Up |
Up |
| ctv(Top) |
Compilation
error |
Compilation
error |
Compilation
error |
| ctv(Middle) |
Compilation
error |
Down |
Compilation
error |
| ctv(Bottom) |
Up |
Down |
Down |
Note : Strongtalk is typed and adopts a contravariant redefinition rule.
See code and results.
Table 13 : Visual Basic
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Note : Column 2 is strange...as if no contravriant were accepted (as
for
Eiffel) but for slot (5,2) ! See code and
results.
Language interoperability using .NET (2 languages case)
Table 14 : C# to (managed) C#, Visual
Basic,
C++
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Up |
Note : Code see C# Client here and
Component
C#,
VisualBasic,
C++
. All results
Table 15 : C++ to (managed) C#, Visual
Basic,
C++
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Compilation error |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Down |
Up |
Note : Code see C++ Client here and
Component
C#,
VisualBasic,
C++
. All results
Table 16 : Visual Basic to
(managed)
C#, Visual Basic, C++
|
u
|
d
|
ud
|
| cv(Top) |
Up |
Up |
Up |
| cv(Middle) |
Up |
Down |
Up |
| cv(Bottom) |
Up |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
| ctv(Middle) |
Compilation error |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Note : Code see VisualBasic Client
here
and Component C#,
VisualBasic,
C++
. All results
The semantics depends on the calling program language.
5. Comparisons for each receivers
Table 17 : Up u = new Up
|
Ada95 |
C++ |
C# |
CLOS/Dylan |
Eiffel |
Java |
OCaml |
Python/Smalltalk |
VisualBasic |
| cv(Top) |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
| cv(Middle) |
Compilation error |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
| cv(Bottom) |
Compilation error |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
Runtime error |
Compilation error |
Compilation error |
Up |
Up |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
Runtime error |
Compilation error |
Compilation error |
Up |
Up |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Up |
Note : functional languages (CLOS, Dylan, OCaml, Smalltalk) accept more
risks...The distinction between OCaml and Smalltalk is due to the OCaml
compiler that would not have compiled code where the type would have
trigger
errors (yellow is safe !).
Table 18 : Down d = new Down
|
Ada95 |
C++ |
C# |
CLOS/Dylan |
Eiffel |
Java |
OCaml |
Python/Smalltalk |
VisualBasic |
| cv(Top) |
Up |
Compilation error |
Up |
Up |
Compilation error |
Up |
Down |
Down |
Up |
| cv(Middle) |
Down |
Down |
Down |
Down |
Down |
Down |
Down |
Down |
Down |
| cv(Bottom) |
Compilation error |
Down |
Down |
Down |
Down |
Down |
Down |
Down |
Down |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
Runtime error |
Compilation error |
Compilation error |
Down |
Down |
Compilation error |
| ctv(Middle) |
Down |
Down |
Down |
Down |
Compilation error |
Down |
Down |
Down |
Down |
| ctv(Bottom) |
Up |
Down |
Down |
Down |
Up |
Compilation error |
Down |
Down |
Up |
Note : Line 1 shows 2 over constraints for C++ and Eiffel. Eiffel
refuses
contravariance. OCaml and Smalltalk are very regular.
Table 19 : Up ud = new Down
|
Ada95 |
C++ |
C# |
CLOS/Dylan |
Eiffel |
Java |
OCaml |
Python/Smalltalk |
VisualBasic |
| cv(Top) |
Up |
Up |
Up |
Up |
Down |
Up |
Down |
Down |
Up |
| cv(Middle) |
Compilation error |
Up |
Up |
Down |
Down |
Up |
Down |
Down |
Up |
| cv(Bottom) |
Compilation error |
Up |
Up |
Down |
Down |
Up |
Down |
Down |
Up |
| ctv(Top) |
Compilation error |
Compilation error |
Compilation error |
Runtime error |
Compilation error |
Compilation error |
Down |
Down |
Compilation error |
| ctv(Middle) |
Compilation error |
Compilation error |
Compilation error |
Down |
Compilation error |
Compilation error |
Down |
Down |
Compilation error |
| ctv(Bottom) |
Up |
Up |
Up |
Down |
Up |
Up |
Down |
Down |
Up |
Note : Eiffel is not type error free. Functional languages accept Down
on line 5 (potential incremental compilation problems).
6. Language interoperability using .NET (3 languages
case)
- A first library is compiled from the FIRST language (among CS -
C# -,
VB
- VisualBasic -, and VC - managed C++). It contains Up, Top, Middle and
Bottom. (3 dll versions)
- A second library is compiled from the SECOND language, using the
FIRST
languages version. It contains the Down class. (3 * 3 = 9 dll versions)
- An executable is built from the THIRD language, using one among
the 9
previous
librairies. (27 exe versions) [source
(100 k)] [source-and-bin
(1.7 M)]
C# Client
The 9 first tables for the C# exe. On each line of 3 tables only the
second
librairy (Down) changes.
Results are regular but for slot (1,2) when Down is programmed in C++.
So, for instance, replacing a VB/dll by a C++/dll will require a exe C#
recompilation !
Table A is a simplified
presentation of these results (where language signature is used as
results).
Tables 20 : CS as Client and Up, Top, Middle, Bottom
| CSCSCS |
u |
d |
ud |
CSVBCS |
u |
d |
ud |
CSVCCS |
u |
d |
ud |
| cv(T) |
U/CS |
U/CS |
U/CS |
cv(T) |
U/CS |
U/CS |
U/CS |
cv(T) |
U/CS |
X |
U/CS |
| cv(M) |
U/CS |
D/CS |
U/CS |
cv(M) |
U/CS |
D/VB |
U/CS |
cv(M) |
U/CS |
D/VC |
U/CS |
| cv(B) |
U/CS |
D/CS |
U/CS |
cv(B) |
U/CS |
D/VB |
U/CS |
cv(B) |
U/CS |
D/VC |
U/CS |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/CS |
D/CS |
U/CS |
ctv(B) |
U/CS |
D/VB |
U/CS |
ctv(B) |
U/CS |
D/VC |
U/CS |
Tables 21 : CS as Client and VisualBasic for Up, Top, Middle
Bottom
| CSCSVB |
u |
d |
ud |
CSVBVB |
u |
d |
ud |
CSVCVB |
u |
d |
ud |
| cv(T) |
U/VB |
U/VB |
U/VB |
cv(T) |
U/VB |
U/VB |
U/VB |
cv(T) |
U/VB |
X |
U/VB |
| cv(M) |
U/VB |
D/CS |
U/VB |
cv(M) |
U/VB |
D/VB |
U/VB |
cv(M) |
U/VB |
D/VC |
U/VB |
| cv(B) |
U/VB |
D/CS |
U/VB |
cv(B) |
U/VB |
D/VB |
U/VB |
cv(B) |
U/VB |
D/VC |
U/VB |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VB |
D/CS |
U/VB |
ctv(B) |
U/VB |
D/VB |
U/VB |
ctv(B) |
U/VB |
D/VC |
U/VB |
Tables 22 : CS as Client and C++ for Up, Top, Middle Bottom
| CSCSVC |
u |
d |
ud |
CSVBVC |
u |
d |
ud |
CSVCVC |
u |
d |
ud |
| cv(T) |
U/VC |
U/VC |
U/VC |
cv(T) |
U/VC |
U/VC |
U/VC |
cv(T) |
U/VC |
X |
U/VC |
| cv(M) |
U/VC |
D/CS |
U/VC |
cv(M) |
U/VC |
D/VB |
U/VC |
cv(M) |
U/VC |
D/VC |
U/VC |
| cv(B) |
U/VC |
D/CS |
U/VC |
cv(B) |
U/VC |
D/VB |
U/VC |
cv(B) |
U/VC |
D/VC |
U/VC |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VC |
D/CS |
U/VC |
ctv(B) |
U/VC |
D/VB |
U/VC |
ctv(B) |
U/VC |
D/VC |
U/VC |
VisualBasic Client
The 9 first tables for the VisualBasic exe. On each line of 3 tables
only
the second librairy (Down) changes.
Sémantique VB
Results are conform to VB semantics but for slot (1,2) and slot (6,2)
when Down is programmed in C++ that triggers a compilation error or
find
in Down instead of Up respectively.
Table B is a simplified
presentation of these results (where language signature is used as
results).
Tables 23 : VB as Client and CS for Up, Top, Middle Bottom
| VBCSCS |
u |
d |
ud |
VBVBCS |
u |
d |
ud |
VBVCCS |
u |
d |
ud |
| cv(T) |
U/CS |
U/CS |
U/CS |
cv(T) |
U/CS |
U/CS |
U/CS |
cv(T) |
U/CS |
X |
U/CS |
| cv(M) |
U/CS |
D/CS |
U/CS |
cv(M) |
U/CS |
D/VB |
U/CS |
cv(M) |
U/CS |
D/VC |
U/CS |
| cv(B) |
U/CS |
D/CS |
U/CS |
cv(B) |
U/CS |
D/VB |
U/CS |
cv(B) |
U/CS |
D/VC |
U/CS |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/CS |
U/CS |
U/CS |
ctv(B) |
U/CS |
U/CS |
U/CS |
ctv(B) |
U/CS |
D/VC |
U/CS |
Tables 24 : VB as Client and Up, Top, Middle Bottom
| VBCSVB |
u |
d |
ud |
VBVBVB |
u |
d |
ud |
VBVCVB |
u |
d |
ud |
| cv(T) |
U/VB |
U/VB |
U/VB |
cv(T) |
U/VB |
U/VB |
U/VB |
cv(T) |
U/VB |
X |
U/VB |
| cv(M) |
U/VB |
D/CS |
U/VB |
cv(M) |
U/VB |
D/VB |
U/VB |
cv(M) |
U/VB |
D/VC |
U/VB |
| cv(B) |
U/VB |
D/CS |
U/VB |
cv(B) |
U/VB |
D/VB |
U/VB |
cv(B) |
U/VB |
D/VC |
U/VB |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VB |
U/VB |
U/VB |
ctv(B) |
U/VB |
U/VB |
U/VB |
ctv(B) |
U/VB |
D/VC |
U/VB |
Tables 25 : VB as Client and C++ for Up, Top, Middle Bottom
| VBCSVC |
u |
d |
ud |
VBVBVC |
u |
d |
ud |
VBVCVC |
u |
d |
ud |
| cv(T) |
U/VC |
U/VC |
U/VC |
cv(T) |
U/VC |
U/VC |
U/VC |
cv(T) |
U/VC |
X |
U/VC |
| cv(M) |
U/VC |
D/CS |
U/VC |
cv(M) |
U/VC |
D/VB |
U/VC |
cv(M) |
U/VC |
D/VC |
U/VC |
| cv(B) |
U/VC |
D/CS |
U/VC |
cv(B) |
U/VC |
D/VB |
U/VC |
cv(B) |
U/VC |
D/VC |
U/VC |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VC |
U/VC |
U/VC |
ctv(B) |
U/VC |
D/VB |
U/VC |
ctv(B) |
U/VC |
D/VC |
U/VC |
C++ Client
The 9 first tables for the C++ exe. On each line of 3 tables only the
second
librairy (Down) changes.
Results are conform to C++ semantics but for slot (6,2) when Down is
programmed in C#!
Table C is a simplified
presentation of these results (where language signature is used as
results).
Tables 26 : VC as Client and CS for Up, Top, Middle Bottom
| VCCSCS |
u |
d |
ud |
VCVBCS |
u |
d |
ud |
VCVCCS |
u |
d |
ud |
| cv(T) |
U/CS |
X |
U/CS |
cv(T) |
U/CS |
X |
U/CS |
cv(T) |
U/CS |
X |
U/CS |
| cv(M) |
U/CS |
D/CS |
U/CS |
cv(M) |
U/CS |
D/VB |
U/CS |
cv(M) |
U/CS |
D/VC |
U/CS |
| cv(B) |
U/CS |
D/CS |
U/CS |
cv(B) |
U/CS |
D/VB |
U/CS |
cv(B) |
U/CS |
D/VC |
U/CS |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/CS |
U/CS |
U/CS |
ctv(B) |
U/CS |
U/CS |
U/CS |
ctv(B) |
U/CS |
U/CS |
U/CS |
Tables 27 : VC as Client and VB for Up, Top, Middle Bottom
| VCCSVB |
u |
d |
ud |
VCVBVB |
u |
d |
ud |
VCVCVB |
u |
d |
ud |
| cv(T) |
U/VB |
X |
U/VB |
cv(T) |
U/VB |
X |
U/VB |
cv(T) |
U/VB |
X |
U/VB |
| cv(M) |
U/VB |
D/CS |
U/VB |
cv(M) |
U/VB |
D/VB |
U/VB |
cv(M) |
U/VB |
D/VC |
U/VB |
| cv(B) |
U/VB |
D/CS |
U/VB |
cv(B) |
U/VB |
D/VB |
U/VB |
cv(B) |
U/VB |
D/VC |
U/VB |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VB |
D/CS |
U/VB |
ctv(B) |
U/VB |
D/VB |
U/VB |
ctv(B) |
U/VB |
D/VC |
U/VB |
Tables 28 : VC as Client and Up, Top, Middle Bottom
| VCCSVC |
u |
d |
ud |
VCVBVC |
u |
d |
ud |
VCVCVC |
u |
d |
ud |
| cv(T) |
U/VC |
X |
U/VC |
cv(T) |
U/VC |
X |
U/VC |
cv(T) |
U/VC |
X |
U/VC |
| cv(M) |
U/VC |
D/CS |
U/VC |
cv(M) |
U/VC |
D/VB |
U/VC |
cv(M) |
U/VC |
D/VC |
U/VC |
| cv(B) |
U/VC |
D/CS |
U/VC |
cv(B) |
U/VC |
D/VB |
U/VC |
cv(B) |
U/VC |
D/VC |
U/VC |
| ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
ctv(T) |
X |
X |
X |
| ctv(M) |
X |
D/CS |
X |
ctv(M) |
X |
D/VB |
X |
ctv(M) |
X |
D/VC |
X |
| ctv(B) |
U/VC |
D/CS |
U/VC |
ctv(B) |
U/VC |
D/VB |
U/VC |
ctv(B) |
U/VC |
D/VC |
U/VC |
.NET faces a real problem. Component are not substituable if they
are
programmed in different languages...
A simplified presentation of the language interaction is shown in
Table A, B and C. We use language signatures (when possible) as
results.
See C#, Visual Basic, C++ signatures.
In table A, the client is in C#. The framework languages are in the
columns.
The extension languages (for Down) are in lines. It is a simplification
of Table 19, 20 and 21.
Tables A : C# as Client
| Extension\Framework |
C# |
VB |
C++ |
| C# |
C# |
C# |
C++ |
| VB |
C# |
C# |
C++ |
| C++ |
C# |
C# |
C++ |
In table B, the client is in Visual Basic. The framework languages
are in the
columns.
The extension languages (for Down) are in lines. It is a simplification
of Table 22, 23 and 24.
Tables B : Visual Basic
as Client
| Extension\Framework |
C# |
VB |
C++ |
| C# |
VB
|
VB
|
C++ |
| VB |
VB |
VB |
C++ |
| C++ |
VB |
C# |
C++ |
In table C, the client is in C++. The framework languages are in the
columns.
The extension languages (for Down) are in lines. It is a simplification
of Table 25, 26 and 27.
Note that the first line has a signature which is not one of studied
languages (Ada95,
C++,
C#,
CLOS,
Dylan,
Eiffel,
Java,
nice,
OCaml,
Python,
Scala,
Smalltalk,
Visual
Basic).
Tables C : C++
as Client
| Extension\Framework |
C# |
VB |
C++ |
| C# |
VB/C++ |
VB/C++ |
VB/C++ |
| VB |
C++ |
C++ |
C++ |
| C++ |
C++ |
C++ |
C++ |
As a temporary conclusion, we can say that the only way to build a
component that always answer as the client expect is to write the
framework/extension with the following couple : C#/VB, C#/C++ and VB/VB
!! (the dark green slots that are always equal to the client
language...).
7. Code transformation
In order to simulate the reasonable
semantics,
it is possible to program the test suite less
naively, using explicit casting or type testing...
8. Conclusion
OO programming may seem natural and easy. Once inheritance is
understood
everything is clear! sure? I hope these experiments and tables ask
questions
...
The proposed tables could be considered as a "language signature" from
the late-binding semantics. An idea to explore is how language
signatures
could be used to forecast interactions of different languages...
To become mature OO paradigm needs a unified semantics and not only
a unified notation...the UML Action Semantics is one step forward, but
still remain confusing on the meaning of the lookup procedure which is,
to my opinion, the key point of OO semantics. [Beu02-3] makes somme
proposals.
I propose two semantics: a reasonable
semantics,
that offers the best specialization and good continuity properties
(when
we consider multiple late-binding) and a pragmatic
one, with "lesser good" properties, but closer to many popular
languages,
and therefore a good candidate. C# implements it and a small and incremental
change in the compiliers of C++ and Java could make all these three
languages
adopting the same late-binding behavior.

The last
conclusion that comes from the observation of tables A,
B
and C
is the following : are components compatible with the object paradigm?
Considering
the most recen results, my position is now to restrict OO programming
languages to a strict invariance redefinition and overriding
forbidance. As for structuring languages it has been useful to limit
the use of the GOTO, I consider that for allowing OO language
interoperability it is necessary to restrict the use of overriding and
overloading.
Future work (I'm looking for funding :-):
- The most pertinent (low cost, minimal research) approach to make
languages
dynamically interoperable seems to adopt the pragmatic semantics and to
make C++ accept to compile slot (1,2) and java slot (6,2). This very
little
semantics shift would lead to a unification af C#, C++ and Java
behavior...
- Another approach consists in selecting a pivot semantics
(pragmatic or
reasonable) and to program and model using this common semantics. Then
different compilers will generate the target language code
corresponding
to the unified semantics - with all explicit cast required ! UML/Action
Semantics could adopt this strategy.
- Accepting diversity, and trying to better undestand late-binding
language
interaction...using "signature operators"...
Thanks
Special thanks to Olivier Aubert who contibutes for Python
and to Martin Monperrus who contributes for Ruby.
And to Roger Rousseau for the Eiffel
code transformation used to make Eiffel
match the "reasonable
semantics".
Thanks to Howard Lovatt for the interesting discussions we have and
the suggestions he made.
Thanks to Tobias Wahl for detecting the Java
semantics change from 1.3 to 1.4.
Références
[Beu02-1] Antoine Beugnard, "OO languages
Late-binding Signature", accepted
at
FOOL 9
(The Ninth International Workshop on Foundations of Object-Oriented
Languages)
, Portland, Oregon, january 19, 2002.
[Beu02-2] Antoine Beugnard, "Une comparaison de langages objet relative
au traitement de la redéfinition de méthode et à
la
liaison dynamique", LMO
2002, Montpellier, 23-25 janvier 2002. (slides pdf)
[Beu02-3] Antoine Beugnard, "Is UML Action Semantics precise enough?
Can Software Engineering do without semantics?", submitted to ICSE
2002
[Beu05] Antoine Beugnard, "Peut-on réaliser des composants avec
un langage à objets ?", LMO
2005, Berne, 9-11 mars 2005.
[Beu06] Antoine Beugnard, "Method overloading and overriding cause
encapsulation flaw", Object-Oriented Programming Languages
and Systems, 21st ACM symposium on Applied Computing (SAC),
Dijon, France, Appril 23-27 2006.
[CM05] Gareth Carter and Rosemary Monahan, "Software Specification,
Implementation and Execution with Perfect", Technical Report, National University of Ireland, Maynooth
Maynooth, Co Kildare, Ireland, Department of computer science,
technical report series, NUIM-CS-TR-2005-07, 2005
updated the 26 may 2011
by Antoine Beugnard,
ENST-Bretagne