EEiiffeffell aanndd CC++++
A comparison between two Object-Oriented languages
Tom Van Cutsem CCllaasssseess aanndd OObbjjeecctsts
Both Eiffel and C++ are statically typed, class- based object-oriented languages. Both regard class definitions as type definitions. Both make a clear distinction between classes and objects. Eiffel is a pure object-oriented language, C++ is impure (multi-paradigm). CCllaasssseess aanndd OObbjjeecctsts CC++++ State encapsulated in ‘data members’. Behaviour encapsulated in ‘memberfunctions’. Manual memory Management Four so called ‘special member functions’: the constructor, the destructor, the copy constructor and the assignment operator. CCllaasssseess aanndd OObbjjeecctsts EEiiffeffell Automatic Garbage Collection Eiffel classes consist of features:
class HELLO create make feature make is -- Print a simple message. do io.put_string ("Hello World") io.put_new_line end end -- class HELLO CCllaasssseess aanndd OObbjjeecctsts EEiiffeffell Two viewpoints on features. From the viewpoint of the defining class, a feature is an attribute, a function or a procedure. From the viewpoint of the client class, a feature is a command or a query. Client Supplier Procedure Command Function Feature Query Attribute CCllaasssseess aanndd OObbjjeecctsts EEiiffeffell The client class does not see the difference between attribute access and a parameterless function call: the Uniform Access Principle
myBalance := myAccount.balance
implemented as an attribute
class ACCOUNT feature balance: INTEGER end CCllaasssseess aanndd OObbjjeecctsts EEiiffeffell The client class does not see the difference between attribute access and a parameterless function call: the Uniform Access Principle
myBalance := myAccount.balance implemented as a function class ACCOUNT feature -- an instance variable thebalance: INTEGER feature -- access the balance balance is do balance := thebalance end CCllaasssseess aanndd OObbjjeecctsts
In C++, classes without ancestors become the root of a new hierarchy. Eiffel has a root class, ANY, which exports features like cloning, comparison, … Eiffel also defines a ‘least class’, NONE, with its sole instance Void. ANY
… … … NONE InInfoforrmmaatitioonn HHiiddiinngg
C++ defines a plethora of keywords to restrict access to members (public,private, protected, friend, …) Eiffel uses ‘export clauses’ to denote which classes (and subclasses) get to see certain features. Attributes can never be assigned to from outside the class, even when ‘public’. class ACCOUNT feature { NONE } -- “Private” balance: INTEGER feature -- “Public” deposit (sum: INTEGER) is do … end feature { ACCOUNT } -- “Protected” connect (bankcomputer: COMPUTER) is do … end feature { COMPUTER } -- COMPUTER is a ”friend” validate (password: STRING) is do … end end InInhheerriitatannccee MMooddeell CC++++ Both Eiffel and C++ allow multiple inheritance. C++ allows ‘private inheritance’ to support ‘subclassing for construction’. Sharing in repeated inheritance is accomplished by ‘virtual inheritance’. Name clashes are solved through explicit qualification of the scope using the scope- resolution (‘::’) operator. InInhheerriitatannccee MMooddeell EEiiffeffell class ASSISTANT inherit STUDENT TEACHER feature … feature adaption clauses are provided to change inherited features. The redefinition clause specifies which methods are overridden. class SAVINGS_ACCOUNT inherit ACCOUNT redefine deposit end feature -- new implementation deposit (sum : INTEGER) is do … end InInhheerriitatannccee MMooddeell EEiiffeffell The renaming clause specifies new names for inherited methods. This is also used to avoid name clashes. class ARRAYED_LIST inherit LIST ARRAY rename count as capacity, item as array_item end feature …
The undefine clause uneffects features which is usefull when a class inherits two implementations for conceptually the same method. InInhheerriitatannccee MMooddeell EEiiffeffell Repeated inheritance is solved on a per-feature basis, rather than on a per-class basis. By renaming a repeated feature, a duplicate is made. If nothing is renamed, then the repeated features are folded into one. InInhheerriitatannccee MMooddeell EEiiffeffell class ASSISTANT inherit TEACHER rename computer_account as faculty_account select faculty_account end STUDENT rename computer_account as student_account end end The Select Clause is used to solve ambiguous calls, for example: p : PERSON create { ASSISTANT } p.make(“John Doe”) … p.computer_account … MMiixxiinnss class Person { string name; public: virtual void display() const { cout << name; } }; template
Axiom (shared) f() = 0
Implementation Interface f() { … } g() { f(); }
Mixin MMiixxiinn EExxaammppllee Axiom class Sequence { virtual void push_front(T elt) = 0; … };
Implementation Interface class Array: public virtual Sequence { … }; class Stack: public virtual Sequence { class List: public virtual Sequence { … }; virtual void push(T elt) { push_front(elt); } }; class Queue: public virtual Sequence { virtual void enqueue(T elt) { push_front(elt); } };
Mixin class ArrayStack: public virtual Array, public virtual Stack { }; class ListQueue: public virtual List, public virtual Queue { }; TTyyppee MMooddeell
Both Eiffel and C++ allow polymorphic assignments based on subclassing (subclassing is interpreted as subtyping). Safe downcasting in C++ through a dynamic_cast:
Derived* derived = dynamic_cast
subclassObj ?= superclassObj if (subclassObj /= Void) then … GGeenneerriiccss
C++ introduces Template functions or classes. Unconstrained: the constraints on the parameters are implicit in the body of the function or class. Eiffel introduces Generic classes with ‘formal generic parameters’. Introduces constrained genericity, for example: class SORTABLE_ARRAY [G COMPARABLE] feature … end DDeessiiggnn BByy CCoonntrtraacctt EEiiffeffell Client classes must conform to a ‘contract’ before being able to use services provided by a supplier. Supplier classes must conform to that ‘contract’ by ensuring they provide the correct services. Supported in Eiffel through pre- and postconditions and class invariants. Preconditions are inherited by ‘OR-ing’ them together, postconditions by ‘AND-ing’. DDeessiiggnn BByy CCoonntrtraacctt EEiiffeffell class ACCOUNT feature balance: INTEGER deposit_count: INTEGER -- number of deposits made since opening all_deposits: DEPOSIT_LIST -- list of deposits since account's opening feature deposit (sum: INTEGER) is precondition require non_negative: sum >= 0 do … postcondition ensure one_more_deposit: deposit_count = old deposit_count + 1 updated: balance = old balance + sum Class end invariant invariant consistent_balance: (all_deposits /= Void) implies (balance = all_deposits.total) zero_if_no_deposits: (all_deposits = Void) implies (balance = 0) end -- class ACCOUNT VVaarriiaannccee RRuulleess CC++++ C++ is agnostic (or non-variant) with respect to method arguments. Allows covariant semantics on return types, which is type safe: class Parent { public: virtual Parent* clone() { … return abase; } }; class Child: public Parent { public: virtual Child* clone() { … return aderived; } }; Parent* aparent = new Child; Parent* result = aparent->clone(); VVaarriiaannccee RRuulleess EEiiffeffell Eiffel uses covariant semantics for both return types and arguments. Allowing covariant semantics on arguments can compromise static typing:
class PLOT class PLOT_3D feature inherit PLOT redefine add end add(covar:DATASAMPLE) is … feature add(covar:DATASAMPLE_3D) is …
plot : PLOT plot3D : PLOT_3D sample : DATASAMPLE plot := plot3D plot.add(sample) VVaarriiaannccee RRuulleess EEiiffeffell Eiffel uses implicit covariance in its generic types: polymorphic assignments between A[X] and A[Y] are possible if X and Y are related through inheritance. This is similar to Java arrays, and also causes type-safety problems:
girlsOnly : VECTOR [PERSON] aBoy : PERSON create {VECTOR[GIRL]} girlsOnly -- allowed with covariance create {BOY} aBoy -- permitted by principle of substitution girlsOnly.append(aBoy) -- girlsOnly now holds a Boy AAnncchhoorreedd TTyyppeess
Eiffel introduces ‘anchored types’ to support working with covariance. Variables declared as: ‘x: like obj’ will be assigned the static type of obj. Anchored types are usually used with Current in a method declaration: when the method is inherited, its type signature changes
acluastso AmCCOaUtNiTcally. class BUSINESS_ACCOUNT feature inherit ACCOUNT owner : PERSON feature set_owner(new: like owner ) is owner : BUSINESS_PERSON … … end end … end MMeeththoodd LLooookkuupp
Eiffel always uses dynamic binding (static binding when appropriate). C++ employs a default policy of static binding.
C++ binding policy
Method is non-virtual Method is virtual Automatic Variables Static Binding Static Binding References & Pointers Static Binding Dynamic Binding MMeeththoodd LLooookkuupp CC++++ Implementation via a ‘virtual function table’ which is shared at run-time by all objects of the same class. Compiler uses lexical addressing through offsets in the vtable. Overridden methods are placed at the same index, but point to different code.
class A { class B: public A { virtual void f() { … } virtual void g() { … } }; virtual void f() { … } }; i i i+1 … …
code for A::f code for B::f code for B::g OOppeenn CC++++
Open C++ is a MOP that allows the programmer to define a metaclass for each class defined in the ‘base program’. Open C++ provides a framework for metaclasses, and provides useful introspective methods and classes (eg. a class that represents the parse-tree of the program, which can then be modified). Classes are represented as ‘class metaobjects’ at the metalevel. Metaclasses are classes whose instances are class metaobjects. Metaclasses inherit from the metaclass ‘Class’. OOppeenn CC++++
Metaclass declaration //base level program metaclass VerboseClass Person; class Person { int age() { return age; } };
//meta-level program Insert sequence operator to class VerboseClass: public Class { avoid interference with base level public: PTree* TranslateMemberCall(Environment* e, Ptree* obj,Ptree* op, Ptree* member, Ptree* arglist) { return PTree::Make(“(print(%p)),%p”,member, Class::TranslateMemberCall(e,obj,op,member,arglist)); } Super send to perform }; actual member call CCoonnccuurrrreennccyy
Neither Eiffel nor C++ support concurrency as a standard language feature. Meyer proposes his own model for concurrency in Eiffel. SSCCOOOOPP
SCOOP (Simple concurrent object-oriented programming) was introduced by Meyer to support concurrency for Object-oriented languages in general. Accomplish a system where synchronisation is implicit in the communication. Communication is represented through method calls. SSCCOOOOPP
In SCOOP, a distinction is made between objects executing on different ‘processors’. When a variable is declared as ‘separate’, this implies the thread of the object that variable is holding is different from the current thread.
Subsystem on processor A Subsystem on processor B
p : separate PERSON p SSCCOOOOPP
Instead of introducing new keywords, concurrent semantics are now defined by redefining the usual object-oriented semantics when dealing with ‘separate’ objects. When invoking a command on a separate object, the caller does not need to wait (asynchronous call). When invoking a query on a separate object, the caller must wait for the result to return (wait-by- necessity). SSCCOOOOPP Preconditions are no longer assertion mechanisms. Applied to separate objects, they are wait conditions. class BOUNDED_BUFFER [G] feature empty, full: BOOLEAN put (x: G) is require not full … ensure not empty end remove is require not empty … ensure not full end … SSCCOOOOPP
When calling a method, the call must wait until every object attached to a separate argument is free and every separate precondition clause is satisfied. Synchronisation is based on object state: the set of messages an object will accept will depend on its state. CCoonncclluussiioonnss
C++: multi-paradigm and efficient. Eiffel: higher-level language, type system contains holes but still safer than C++. The efficiency policy of C++ (stack-allocation and static binding, no garbage collection) conflicts with Object-oriented programming. Neither language provides standard metaprogramming or concurrency facilities.