The Precursor construct
This document describes a proposal, initially by Bertrand Meyer, to the
language committee of NICE, the Nonprofit International Consortium for
Eiffel. The proposal was approved by the language committee by vote in
October of 1997. The Board of NICE is expected to ratify it shortly.
This short document describes the mechanism informally. It is an ISE
document and does not commit NICE. A companion document contains the text
of the formal proposal as adopted by the NICE
language committee, and you will find here
the modification that ISE did with version 4.5.
Overview
This is a proposal for an extension to the Eiffel language. The author
takes full responsibility for the wording of the proposal and for any
error or inconsistency in it.
The credit for the basic invention, however, is to be shared between
the following people (in alphabetical order): Roger Browne, James McKim,
Bertrand Meyer, Frieder Monninger, Steve Tynor and Kim Waldén.
Rationale and background
In writing classes, it frequently occurs that the redefinition of a
routine r must rely on the original algorithm. A typical scheme is
r (arguments) is
-- Redefined version
do
"Parent version of r" (arguments)
"Some complementary actions"
end
although other variants also occur (for example the actual arguments
might be different from the formal ones, or the complementary actions
might come before rather than after the call to the original version).
In the language defined by the book "Eiffel: The Language"
(Prentice Hall, 1992, hereafter "ETL"), the mechanism that
achieves this result is based on repeated inheritance. The redefining
class inherits a second time from the parent containing the original
version of r; that second inheritance clause does not redefine r,
so that the original version remains available. That version will be
renamed, and typically it will be neither selected nor exported. The
scheme is
indexing
description:
"A class that redefines r while using the %
original A version in the redefinition"
class B inherit
A
redefine
r
select
r
end
A
rename
r as original_r
export
{NONE} all
end
feature
r (...) is
do
original_r (...)
other_actions
end
... Other feature declarations or redeclarations
end -- class B
This mechanism clearly works, and has not been a major impediment to
the development of large, highly successful Eiffel systems, or to the
teaching of Eiffel to tens of thousands of students of all levels.
It has been criticized, however, particularly on the basis of the
following considerations:
- 1. It is a little difficult to
explain to beginners. There is a discrepancy between the relative
simplicity of the goal (gaining access to the original version of a
redefined feature) and the heaviness of the solution, involving a new
Parent clause, export, rename and select.
- 2. Even for non-novices, the
heaviness may become a nuisance when a non-trivial inheritance structure
is involved. For example B may redefine other features beyond A,
or may already be a repeated descendant of A. This can make the
Inheritance clause more complicated than would seem desirable.
The present proposal - resulting from extensive discussions on both
comp.lang.eiffel and the NICE Language Committee, initiated by a detailed
posting by Roger Browne on comp.lang.eiffel in June of 1995 - is an
attempt to address the issue simply and effectively. The challenge was to
simplify the task at hand - providing access to the original version of a
redefined feature - while respecting the following uncontrovertible
obligations:
- Keeping the language simple.
- Not introducing redundancy.
- Not violating correctness
requirements.
- Not violating information hiding
(which excludes in particular a Smalltalk-like super mechanism).
- Not impairing the ability to produce
efficient compilers.
- Not complicating in any significant
way the structure of existing compilers.
The result is based on the following idea: do not define the
original r as a "feature of the class" B; instead,
provide a limited mechanism that allows the body of a redefined routine
such as r - and only such a body - to refer to the original,
under a special syntax.
This, we hope, achieves the goal of a minimal extension that solves one
of the very few reported sore points of Eiffel development without
complicating the language significantly or affecting the spirit of its
design.
Auxiliary effect
It has been stated that a good language extension should whenever
possible solve several problems at once. One of the consequences of the
"Precursor" extension described below is a slight change to the
inheritance mechanism which, we think, will improve the language. (This
change conforms to the semantics which was already implemented by ISE
Eiffel, departing from the ETL semantics.)
This secondary change is a generalization of the Join mechanism, used
to merge n inherited features with n >= 2. Under the ETL
semantics at most one of these features may be effective. Under the new
semantics this rule is removed; any number of effective and deferred
routines may be "joined" (merged) provided all the effective
ones figure in Redefine clauses in the corresponding Parent parts.
This appears to simplify both the semantic description of the language
and its practical use, avoiding the need to undefine n-1 effective
routines, artificially chosen, out of n that one may want to join.
A practical note for OOSC-2 readers
The book Object-Oriented Software
Construction, second edition (Prentice Hall, 1997) describes the
mechanism with a small syntactic differences: it uses double braces, as in
{{PARENT}}, rather than single braces as in {PARENT}.
To avoid any confusion, ISE's compiler accepts both form. The
single-brace form is the recommended form.
The formal proposal
The precise proposal as approved by the NICE language committee appears
in a separate page.
|