Revision as of 17:58, 22 August 2006 editBertrand Meyer (talk | contribs)169 edits Please do not use my material without my permission. It is now available elsewhere (see talk page).← Previous edit | Revision as of 18:01, 22 August 2006 edit undoIdeogram (talk | contribs)11,726 edits rv; it's not your material anymoreNext edit → | ||
Line 43: | Line 43: | ||
Eiffel shuns coding tricks or coding techniques intended as ] hints to the compiler. The aim is not only to make the code more readable, but also to allow programmers to concentrate on the important aspects of a program without getting bogged down in implementation details. Eiffel's simplicity is intended to promote simple, extendible, reusable and reliable answers to computing problems. Compilers provide extensive optimization techniques such as automatic inlining which remove part of the burden of optimization from the programmer, with the aim of producing extremely efficient code comparable to e.g. C++. | Eiffel shuns coding tricks or coding techniques intended as ] hints to the compiler. The aim is not only to make the code more readable, but also to allow programmers to concentrate on the important aspects of a program without getting bogged down in implementation details. Eiffel's simplicity is intended to promote simple, extendible, reusable and reliable answers to computing problems. Compilers provide extensive optimization techniques such as automatic inlining which remove part of the burden of optimization from the programmer, with the aim of producing extremely efficient code comparable to e.g. C++. | ||
==Design by Contract in Eiffel== | |||
(With this section some code examples start appearing. The use of fonts and color are part of the Eiffel standard style. See "Style rules" below.) | |||
The concepts of ] are central to Eiffel. The mechanisms are tightly integrated with the language. The basic constructs are: | |||
*Routine precondition | |||
*Routine postcondition | |||
*Class invariant | |||
In addition, the language supports a "Check instruction" (a kind of "assert") and, in the syntax for loops, clauses for a loop invariant and a loop variant. | |||
As defined in the Design by Contract methodology, contracts guide redefinition of features in inheritance. Specifically, in a redefinition: | |||
*The precondition can only be weakened, to ensure that any call that met the requirements of the original version still meets those of the redefined one. The keyword in that case is no longer <code><font color=blue>'''require'''</font></code> but <code><font color=blue>'''require else'''</font></code>. | |||
*The postcondition can only be strengthened, to ensure that any result guaranteed by the original version is still provided by the redefined one. The keyword in that case is no longer <code><font color=blue>'''ensure'''</font></code> but <code><font color=blue>'''ensure then'''</font></code>. | |||
==Other language mechanisms== | |||
===Overall structure=== | |||
An Eiffel "'''system'''" (or "program") is a collection of '''classes'''. The class is the major unit of decomposition. | |||
At the level above classes: there is a notion of "'''cluster'''". A cluster is essentially a group of classes, and possibly subclusters since clusters can be nested. But there is no language construct for "cluster"; this is an organizational tool left to the environment. Typically (but again this is not prescribed): | |||
*Each class will be in a separate file (standard convention: x.e for the file name if the class is called X). | |||
*Each cluster will be in a directory (folder) containing such class files; subclusters are in subdirectories. | |||
At the level below classes: a class contains '''features''' (roughly corresponding to "members" in e.g. C++), a class invariant, and some other properties such as a "notes" section for documentation. | |||
Any system must have a class designated as "root", and one of its creation procedures designated as "root procedure". Executing the system consists of creating an instance of the root class and executing its root procedure. (Of course this generally creates new objects, calls new features etc.) | |||
===Features, commands, queries=== | |||
The primary characteristic of a class is that it contains a set of features. As a class represents a set of run-time objects (its instances), a feature is an operation on these objects. Operations are of two kinds: | |||
*Queries, which give information about an instance. | |||
*Commands, which modify an instance. | |||
This distinction is important to the Eiffel method. In particular: | |||
*Uniform Access Principle: from the outside, whether a query is an attribute (field in each object) or a function (algorithm) should not make any difference. For example a_vehicle.speed could be an attribute, accessed from the object's representation; or it could be computed by a function that divides distance by time. The notation is the same in both cases, so that it's easy to change representation without affecting the rest of the software. | |||
*]: Queries must not modify the instance. This is not a language rule but a methodological principle. So in good Eiffel style one does not find "get" function that change something and return a result; instead there are commands (procedures) to change objects, and queries to obtain information about the object, resulting from preceding changes. | |||
===Feature names and no-overloading=== | |||
An important property of Eiffel is that a class is fundamentally a mapping from feature names to features. More plainly said this means that one name, within one class, means one thing. This keeps things simple and in particular is what makes the multiple inheritance mechanism possible (see below). | |||
Names can, of course, be reused in different classes, but in a given class if you need another feature you'll have to invent another name. This is really no limitation since the conventional kinds of ] are, in an object-oriented perspective, applied to different classes. For example if you want to have several versions of <code><font color=blue>"+"</font></code>: | |||
<code><font color=blue>''a'' + ''b''</font></code> for <code><font color=blue>''a'', ''b'': ''INTEGER''</font></code> | |||
<code><font color=blue>''a'' + ''b''</font></code> for <code><font color=blue>''a'', ''b'': ''REAL''</font></code> | |||
<code><font color=blue>''a'' + ''b''</font></code> for <code><font color=blue>''a'', ''b'': ''VECTOR'' </font></code> | |||
then in Eiffel it simply means that the three classes involved each have a feature | |||
<code><font color=blue>''plus'' '''alias''' "+" (''other'': ''XXX''): ''XXX''</font></code> | |||
where <code><font color=blue>''XXX''</font></code> is the given class (<code><font color=blue>''INTEGER''</font></code>, <code><font color=blue>''REAL''</font></code>, <code><font color=blue>''VECTOR'' )</font></code>. (See "Operator and bracket syntax, assigner commands" below.) All the usual forms of operator overloading are thus supported; in fact the mechanism (unlike in most languages) leaves considerable freedom in making up new operators, as may be needed in scientific and engineering applications. What is not possible is the kind of argument overloading where a given class has both a feature <code><font color=blue>''f'' (''x'': ''X'')</font></code> and another <code><font color=blue>''f'' (''y'': ''Y'')</font></code> with the same names. Meyer has argued <ref>Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October-November 2001, available </ref> that such overloading is useless, damages readability, and complicates the language mechanism needlessly. | |||
===Genericity=== | |||
Classes can be generic, to express that they are parameterized by types. Generic parameters appear in square brackets: | |||
<code><font color="blue">'''class''' ''LIST'' ...</font></code> | |||
G is known as a "formal generic parameter". (Eiffel reserves "argument" for routines, and uses "parameter" only for generic classes.) With such a declaration G represents within the class an arbitrary type; so a function can return a value of type G, and a routine can take an argument of that type: | |||
<code><font color="blue">''item'': ''G'' '''do''' ... '''end''' | |||
''put'' (''x'': ''G'') '''do''' ... '''end'''</font></code> | |||
The <code><font color="blue">''LIST'' </font></code> and <code><font color="blue">''LIST'' </font></code> are "generic derivations" of this class. Permitted combinations(with <code><font color="blue">''n'': ''INTEGER''</font></code>, <code><font color="blue">''w'': ''WORD''</font></code>, <code><font color="blue">''il'': ''LIST'' </font></code>, <code><font color="blue">''wl'': ''LIST'' </font></code>) are | |||
<code><font color="blue">''n'' := ''il''.''item'' | |||
''wl''.''put'' (''w'')</font></code> | |||
<code><font color="blue">''INTEGER''</font></code> resp. <code><font color="blue">''WORD''</font></code> are the "actual generic parameters" in these generic derivations. | |||
It is also possible to have '''constrained''' formal parameters, for which the actual parameter must inherit from a given class, the "constraint". For example in | |||
<code><font color="blue">'''class''' ''HASH_TABLE'' </font></code> | |||
a derivation <code><font color="blue">''HASH_TABLE'' </font></code> is valid only if <code><font color="blue">STRING</font></code> inherits from <code><font color="blue">''HASHABLE''</font></code> (as it it indeed does in typical Eiffel libraries). Within the class, having <code><font color="blue">KEY</font></code> constrained by <code><font color="blue">''HASHABLE''</font></code> means that for <code><font color="blue">''x'': ''KEY''</font></code> it is possible to apply to <code><font color="blue">x</font></code> all the features of <code><font color="blue">''HASHABLE''</font></code>, as in <code><font color="blue">''x''.''hash_code''</font></code>. | |||
===Inheritance basics=== | |||
To inherit from one or more others, a class will include a <code><font color=blue>'''inherit'''</font></code> clause at the beginning: | |||
<code><font color=blue>'''class''' ''C'' '''inherit''' | |||
''A'' | |||
''B'' | |||
... Rest of class declaration ...</font></code> | |||
The class may redefine (override) some or all of the inherited features. This must be explicitly announced at the beginning of the class through a <code><font color=blue>'''redefine'''</font></code> subclause of the inheritance clause, as in | |||
<code><font color=blue>'''class''' ''C'' '''inherit''' | |||
''A'' | |||
'''redefine''' ''f'', ''g'', ''h'' '''end''' | |||
''B'' | |||
'''redefine''' ''u'', ''v'' '''end'''</font></code> | |||
{{ Underconstruction }} | |||
===Multiple and repeated inheritance=== | |||
{{ Underconstruction }} | |||
===Renaming=== | |||
A class that inherits from one or more others gets all its features, by default under their original names. It may, however, change their names through a <code><font color=blue>'''rename'''</font></code> clauses. This is required in the case of multiple inheritance if there are name clashes between inherited features; without renaming, the resulting class would violate the no-overloading principle noted above and hence would be invalid. | |||
===Tuples=== | |||
Tuples types may be viewed as a simple form of class, providing only attributes and the corresponding "setter" procedure. A typical tuple type reads | |||
<code><font color=blue>''TUPLE'' </font></code> | |||
and could be use to describe a simple notion of birth record if a class is not needed. An instance of such a tuple is simply a sequence of values with the given types, given in brackets, such as | |||
<code><font color=blue></font></code> | |||
Components of such a tuple can be accessed as if the tuple tags were attributes of a class, for example if <code><font color=blue>''t'']</font></code> has been assigned the above tuple then <code><font color=blue>''t''.''weight'']</font></code> has value 3.5. | |||
Thanks to the notion of assigner command (see below), dot notation can also be used to assign components of such a tuple, as in | |||
<code><font color=blue>''t''.''weight'' := ''t''.''weight'' + 0.5</font></code> | |||
The tuple tags are optional, so that it is also possible to write a tuple type as <code><font color=blue>''TUPLE'' </font></code>. (In some compilers this is the only form of tuple, as tags were introduced with the ECMA standard.) | |||
The precise specification of e.g. <code><font color=blue>''TUPLE'' </font></code> is that it describes sequences of ''at least'' three elements, the first three being of types <code><font color=blue>''A''</font></code>, <code><font color=blue>''B''</font></code>, <code><font color=blue>''C''</font></code> respectively. As a result <code><font color=blue>''TUPLE'' </font></code> conforms to (may be assigned to) <code><font color=blue>''TUPLE'' </font></code>, to <code><font color=blue>''TUPLE'' </font></code> and to <code><font color=blue>''TUPLE''</font></code> (without parameters), the topmost tuple type to which all tuple types conform. | |||
===Agents=== | |||
Eiffel provides an "agent" mechanism to wrap operations into objects. This is useful for iteration, event-driven programming, and other applications for which it is useful to pass operations around the program structure. Agents correspond ] and to ]; they make it possible to combine the object-oriented paradigm with a significant set of mechanisms available in ] languages. | |||
For example, to iterate a certain action over a list, it suffices to write | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''my_action'')</font></code> | |||
or, if the action is to be executed only on elements satisfying a certain condition: | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''my_action'', '''agent''' ''my_condition'')</font></code> | |||
In these examples, <code><font color=blue>''my_action''</font></code> and <code><font color=blue>''my_condition''</font></code> are routines. Prefixing them with <code><font color=blue>'''agent'''</font></code> yields an object that represents the corresponding routine with all its properties, in particular the ability to be called with the appropriate arguments. So if <code><font color=blue>''a''</font></code> represents that object (for example because <code><font color=blue>''a''</font></code> is the argument to <code><font color=blue>''do_all''</font></code>), the instruction | |||
<code><font color=blue>''a''.''call'' ()</font></code> | |||
will call the original routine with the argument <code><font color=blue>''x''</font></code>, as if we had directly called the original routine: <code><font color=blue>''my_action'' (''x'')</font></code>. Arguments to <code><font color=blue>''call''</font></code> are passed as a tuple, here <code><font color=blue></font></code>. | |||
It is possible to keep some arguments to an agent '''open''' and make others '''closed'''. The open arguments are passed as arguments to <code><font color=blue>''call''</font></code>: they are provided at the time of agent ''use''. The closed arguments are provided at the time of agent ''definition''. For example, if <code><font color=blue>''action2''</font></code> has two arguments, the iteration | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''action2'' ('''?''', ''y'')</font></code> | |||
iterates <code><font color=blue>''action2'' (''x'', ''y'')</font></code> for successive values of <code><font color=blue>''x''</font></code>, where the second arguments remained set to <code><font color=blue>''y''</font></code>. The question mark <code><font color=blue>'''?'''</font></code> indicates an open argument; <code><font color=blue>''y''</font></code> is a closed argument of the agent. Note that the basic syntax <code><font color=blue>'''agent''' ''f''</font></code> is a short hand for <code><font color=blue>'''agent''' ''f'' ('''?''', '''?''', ...)</font></code> with all arguments open. It is also possible to make the ''target'' of an agent open through the notation <code><font color=blue>{''T''}'''?'''</font></code> where <code><font color=blue>''T''</font></code> is the type of the target. | |||
The distinction between open and closed operands (operands = arguments + target) corresponds to the distinction between bound and free variables in ]. An agent expression such as <code><font color=blue>''action2'' ('''?''', ''y'')</font></code> with some operands closed and some open corresponds to a version of the original operation ] on the closed operands. | |||
The agent mechanism has been recently generalized to allow defining an agent without reference to an existing routine (such as <code><font color=blue>''my_action''</font></code>, <code><font color=blue>''my_condition''</font></code>, <code><font color=blue>''action2''</font></code>), through inline agents as in | |||
<code><font color=blue>''my_list''.''do_all'' | |||
('''agent''' (''x'': ''INTEGER'') | |||
'''require''' | |||
positive: ''x'' > 0 | |||
'''do''' | |||
''x'' := ''x'' – 1 | |||
'''ensure''' | |||
''x'' = '''old''' ''x'' – 1 | |||
'''end''' | |||
)</font></code> | |||
The inline agent passed here can have all the trappings of a normal routine, including precondition, postcondition, rescue clause (not used here), and a full signature. This avoids defining routines when all that's needed is a computation to be wrapped in an agent. This is useful in particular for contracts, as in an invariant clause that expresses that all elements of a list are positive: | |||
<code><font color=blue>''my_list''.''for_all'' ('''agent''' (''x'': ''INTEGER''): ''BOOLEAN'' '''do''' ''Result'' := (''x'' > 0) '''end''')</font></code> | |||
The current agent mechanism leaves a possibility of run-time type error (if a routine with ''n'' arguments is passed to an agent expecting ''m'' arguments with ''m'' < ''n''). This can be avoided by a run-time check through the precondition <code><font color=blue>''valid_arguments''</font></code> of <code><font color=blue>''call''</font></code>. Several proposals for a purely static correction of this problem are available, including a language change proposal by Ribet et al. <ref>Philippe Ribet, Cyril Adrian, Olivier Zendra, Dominique Colnet: ''Conformance of agents in the Eiffel language'', in ], vol. 3, no. 4, April 2004, Special issue: TOOLS USA 2003, pp. 125-143. Available on line from the </ref>. | |||
===Once routines=== | |||
A routine can be declared "once" (with the keyword <code><font color=blue>'''once'''</font></code> replacing the more common <code><font color=blue>'''do'''</font></code>) to indicate that it will only be executed on the first call. Subsequent calls have no further effect; in the case of a function, they return the same value as the first, for example a reference to the same object. | |||
"Once" functions serve in particular to provide shared objects; the first call will create the object, subsequent ones will return the reference to that object. The typical scheme is | |||
<code><font color=blue>''shared_object'': ''SOME_TYPE'' | |||
'''do''' | |||
'''create''' '''Result'''.''make'' (''args'') -- This creates the object and returns a reference to it through '''Result''' | |||
'''end'''</font></code> | |||
While the reference remains the same, later calls of the form <code><font color=blue>''shared_object''.''do_something''</font></code> can change the ''content'' of the object. | |||
"Once" procedures can take care of initialization: several clients of a certain libraries can include a call to the initialization procedure, but only the first such call to happen will actually have an effect. The goal is to achieve decentralized initialization, avoiding the need for an initialization module (which could damage the modular structure of the program). | |||
The ECMA specification allows variants of "once" (qualified by a keyword in parentheses, e.g. <code><font color=blue>'''once''' (THREAD)</font></code>: once per process, once per thread, once per object. This is not, however, fully implemented yet by current compilers (typically, only PROCESS and THREAD). | |||
===Conversions=== | |||
Eiffel provides a mechanism to allow conversions between various types. The mechanisms coexists with inheritance and complements it. To avoid any confusion between the two mechanisms, the design enforces the following principle: | |||
(Conversion principle) A type may not both conform and convert to another | |||
For example <code><font color=blue>''NEWSPAPER''</font></code>may conform to to <code><font color=blue>''PUBLICATION''</font></code>, but <code><font color=blue>''INTEGER''</font></code> converts to <code><font color=blue>''REAL''</font></code> (and does not inherit from it). | |||
The conversion mechanism simply generalizes the ad hoc conversion rules (such as indeed between <code><font color=blue>''INTEGER''</font></code>and <code><font color=blue>''REAL''</font></code>) that exist in most programming languages, making them applicable to any type as long as the above principle is observed. For example a <code><font color=blue>''REAL''</font></code> class may be declared to convert to <code><font color=blue>''REAL''</font></code>; this makes it possible to create a string from a date simply through | |||
<code><font color=blue>''my_string'' := ''my_date''</font></code> | |||
as a shortcut for using an explicit object creation with a conversion procedure: | |||
<code><font color=blue>'''create''' ''my_string''.make_from_date (''my_date'')</font></code> | |||
To make the first form possible as a synonym for the first, it suffices to list the creation procedure (constructor) <code><font color=blue>''make_from_date''</font></code> in a <code><font color=blue>'''convert'''</font></code> clause at the beginning of the class. | |||
As another example, if there is such a conversion procedure listed from <code><font color=blue>''TUPLE'' ]</font></code>, then one can directly assign a tuple to a date, causing the appropriate conversion, as in | |||
<code><font color=blue>''Bastille_day'' := </font></code> | |||
===Exception handling=== | |||
{{ Underconstruction }} | |||
===Operator and bracket syntax, assigner commands=== | |||
Eiffel's view of computation is completely object-oriented in the sense that every operation is relative to an object, the "target". So for example an addition | |||
<code><font color=blue>''a'' + ''b''</font></code> | |||
is conceptually understood as if it were a function call | |||
<code><font color=blue>''a''.''plus'' (''b'')</font></code> | |||
with target <code><font color=blue>''a''</font></code>, feature <code><font color=blue>''plus''</font></code> and argument <code><font color=blue>''b''</font></code>. | |||
Of course is the conventional syntax and usually preferred. Operator syntax makes it possible to use either form by declaring the feature (for example in <code><font color=blue>''INTEGER''</font></code>, but this applies to other basic classes and can be used in any other for which such an operator appropriate): | |||
<code><font color=blue>''plus'' '''alias''' "+" (''other'': ''INTEGER''): ''INTEGER'' | |||
... Normal function declaration... | |||
'''end'''</font></code> | |||
The range of operators that can be used as "alias" is quite broad; they include predefined operators such as "+" but also "free operators" made of non-alphanumeric symbols. This makes it possible to design special infix and prefix notations, for example in mathematics and physics applications. | |||
Every class may in addition have ''one'' function aliased to "", the "bracket" operator, allowing the notation <code><font color=blue>''a'' </font></code> as a synonym for <code><font color=blue>''a''.''f'' (''i'', ...)</font></code> where <code><font color=blue>''f''</font></code> is the chosen function. This is particularly useful for container structures such as arrays, hash tables, lists etc. For example access to an element of a hash table with string keys can be written | |||
<code><font color=blue>''number'' := ''phone_book'' </font></code> | |||
"Assigner commands" are a companion mechanism designed in the same spirit of allowing well-established, convenient notation reinterpreted in the framework of object-oriented programming. Assigner commands allow assignment-like syntax to call "setter" procedures. An assignment proper can never be of the form <code><font color=blue>''a''.''x'' := ''v'']</font></code> as this violates information hiding; you have to go for a setter command (procedure). For example the hash table class can have the function and the procedure | |||
<code><font color=blue>''item'' '''alias''' "" (''key'': ''STRING''): ''ELEMENT''</font></code> <code><font color=blue> | |||
-- The element of key ''key'' | |||
-- ("Getter" query) | |||
'''do''' | |||
... | |||
'''end'''</font></code> | |||
<br/> | |||
<code><font color=blue>''put''(''e'': ''ELEMENT''; ''key'': ''STRING''): ''ELEMENT'' | |||
-- Insert the element ''e'', associating it with the key ''key''. | |||
-- ("Setter" command) | |||
'''do''' | |||
... | |||
'''end'''</font></code> | |||
Then to insert an element you have to use an explicit call to the setter command: | |||
<code><font color=blue>''phone_book''.''put'' (''New_person'', "JILL SMITH")</font></code> | |||
It is possible to write this equivalently as | |||
<code><font color=blue>''phone_book'' := ''New_person''</font></code> | |||
(in the same way that <code><font color=blue>''phone_book'' </font></code> is a synonym for <code><font color=blue>''number'' := ''phone_book''.''item'' ("JILL SMITH")</font></code>), provided the declaration of <code><font color=blue>''item''</font></code> now starts (replacement for ) with | |||
<code><font color=blue>''item'' '''alias''' "" (''key'': ''STRING''): ''ELEMENT'' '''assign''' ''put''</font></code> | |||
This declares <code><font color=blue>''put''</font></code> as the assigner command associated with <code><font color=blue>''item''</font></code> and, combined with the bracket alias, makes legal and equivalent to . (It could also be written, without taking advantage of the bracket, as <code><font color=blue>''phone_book''.''item'' ("JILL SMITH") := ''New_person''</font></code>. | |||
===Lexical and syntax properties=== | |||
Eiffel is not case-sensitive. The tokens <code><font color=blue>''make''</font></code>, <code><font color=blue>''maKe''</font></code> and <code><font color=blue>''MAKE''</font></code> all denote the same identifier. See, however, the "style rules" below. | |||
Comments are introduced by <code><font color="blue">--</font></code> (two consecutive dashes) and extend to the end of the line. | |||
The semicolon, as instruction separator, is optional. Most of the time the semicolon is just omitted, except to separate multiple instructions on a line. This results in less clutter on the program page. | |||
There is no nesting of feature and class declarations. As a result the structure of an Eiffel class is simple: some class-level clauses (inheritance, invariant) and a succession of feature declarations, all at the same level. | |||
It is customary to group features into separate "feature clauses" for more readability, with a standard set of basic feature tags appearing in a standard order, for example: | |||
<code><font color="blue">'''class''' ''HASH_TABLE'' '''inherit''' | |||
''TABLE'' <br/> | |||
'''feature''' -- Initialization | |||
... Declarations of initialization commands (creation procedures/constructors) ...<br/> | |||
'''feature''' -- Access | |||
... Declarations of non-boolean queries on the object state, e.g. ''item'' ...<br/> | |||
'''feature''' -- Status report | |||
... Declarations of boolean queries on the object state, e.g. ''is_empty'' ...<br/> | |||
'''feature''' -- Element change | |||
... Declarations of commands that change the structure, e.g. ''put'' ...<br/> | |||
etc. | |||
'''end''' </font></code> | |||
In contrast to most ]s, Eiffel makes a clear distinction between expressions and instructions. This is in line with the ] principle of the Eiffel method. | |||
===Style rules=== | |||
Eiffel is distinguished by strong style rules, designed to enforce a consistent look-and-feel. | |||
While the language is case-insensitive, the style standards prescribe the use of all-capitals for class names (<code><font color=blue>''LIST''</font></code>), all-lower-case for feature names (<code><font color=blue>''make''</font></code>), and initial capitals for constants (<code><font color=blue>''Avogadro''</font></code>). | |||
The recommended style also suggests underscore to separate components of a multi-word identifier, as in <code><font color=blue>''average_temperature''</font></code>. | |||
The specification of Eiffel includes guidelines for displaying software texts in typeset formats: keywords in bold, user-defined identifiers and constants are shown in <code><font color=blue>''italics''</font></code>, comments, operators, and punctuation marks in <code><font color=blue>''roman''</font></code>, with program text in <code><font color=blue>blue</font></code> as in the present article to distinguish it from explanatory text. | |||
===Basic instructions=== | ===Basic instructions=== |
Revision as of 18:01, 22 August 2006
Paradigm | object-oriented |
---|---|
Designed by | Bertrand Meyer |
Developer | Bertrand Meyer & Eiffel Software |
First appeared | 1986 |
Stable release | 4.2 / Feb 6, 1998 |
Typing discipline | static typing, strong typing |
Major implementations | |
EiffelStudio, SmartEiffel, Visual Eiffel | |
Influenced by | |
Ada, Simula, Z | |
Influenced | |
Sather, Ruby, Java, C# |
Eiffel is an ISO-standardized object-oriented programming language, based on a conscious design methodology, intended for the production of quality software with a particular emphasis on extendibility, reusability, reliability and programmer productivity.
With roots going back to 1985, Eiffel is a mature language with development environments available from multiple suppliers. Although less well known than some other object-oriented approaches, Eiffel is used by large projects in various industries (finance, aerospace, health care, games and others) as well as for teaching programming in academia.
The language design is closely connected with the method, based on a set of principles: Design by contract, Command-query separation, Uniform access principle, Single choice principle, Open-closed principle, Option-Operand separation and others.
Many concepts initially introduced by Eiffel have later found their way into other languages such as Java and C#, and Eiffel continues to try language design ideas, particularly through the ECMA/ISO standardization process.
Overview
Key characteristics of the language, explained in more detail below, include:
- Mechanisms supporting Design by contract (routine pre- and postconditions, class invariants), tightly integrated with the inheritance mechanism and other language constructs.
- Object-oriented program structure; classes are the basic decomposition unit.
- Static typing.
- Support for automatic memory management, typically implemented by garbage collection).
- Central role of inheritance including multiple inheritance and mechanisms to make it safe (renaming, redefinition, "select", non-conforming inheritance).
- A uniform type system handling both value and reference semantics, where all types including basic types such as INTEGER are based on classes.
- Genericity, constrained and unconstrained.
- "Agents" (objects wrapping computations, closely connected with closures and lambda calculus.
- "Once" routines (evaluated only the first time around), for object sharing and decentralized initialization.
- Keyword-based syntax ALGOL/Pascal tradition but separator-free (semicolon is optional); operator syntax available for routines.
Design goals
The Eiffel language aims to promote clear and elegant programming. Eiffel emphasizes declarative statements over procedural code, and eliminates the need for bookkeeping instructions.
Eiffel shuns coding tricks or coding techniques intended as optimization hints to the compiler. The aim is not only to make the code more readable, but also to allow programmers to concentrate on the important aspects of a program without getting bogged down in implementation details. Eiffel's simplicity is intended to promote simple, extendible, reusable and reliable answers to computing problems. Compilers provide extensive optimization techniques such as automatic inlining which remove part of the burden of optimization from the programmer, with the aim of producing extremely efficient code comparable to e.g. C++.
Design by Contract in Eiffel
(With this section some code examples start appearing. The use of fonts and color are part of the Eiffel standard style. See "Style rules" below.)
The concepts of Design by Contract are central to Eiffel. The mechanisms are tightly integrated with the language. The basic constructs are:
- Routine precondition
- Routine postcondition
- Class invariant
In addition, the language supports a "Check instruction" (a kind of "assert") and, in the syntax for loops, clauses for a loop invariant and a loop variant.
As defined in the Design by Contract methodology, contracts guide redefinition of features in inheritance. Specifically, in a redefinition:
- The precondition can only be weakened, to ensure that any call that met the requirements of the original version still meets those of the redefined one. The keyword in that case is no longer
require
butrequire else
.
- The postcondition can only be strengthened, to ensure that any result guaranteed by the original version is still provided by the redefined one. The keyword in that case is no longer
ensure
butensure then
.
Other language mechanisms
Overall structure
An Eiffel "system" (or "program") is a collection of classes. The class is the major unit of decomposition.
At the level above classes: there is a notion of "cluster". A cluster is essentially a group of classes, and possibly subclusters since clusters can be nested. But there is no language construct for "cluster"; this is an organizational tool left to the environment. Typically (but again this is not prescribed):
- Each class will be in a separate file (standard convention: x.e for the file name if the class is called X).
- Each cluster will be in a directory (folder) containing such class files; subclusters are in subdirectories.
At the level below classes: a class contains features (roughly corresponding to "members" in e.g. C++), a class invariant, and some other properties such as a "notes" section for documentation.
Any system must have a class designated as "root", and one of its creation procedures designated as "root procedure". Executing the system consists of creating an instance of the root class and executing its root procedure. (Of course this generally creates new objects, calls new features etc.)
Features, commands, queries
The primary characteristic of a class is that it contains a set of features. As a class represents a set of run-time objects (its instances), a feature is an operation on these objects. Operations are of two kinds:
- Queries, which give information about an instance.
- Commands, which modify an instance.
This distinction is important to the Eiffel method. In particular:
- Uniform Access Principle: from the outside, whether a query is an attribute (field in each object) or a function (algorithm) should not make any difference. For example a_vehicle.speed could be an attribute, accessed from the object's representation; or it could be computed by a function that divides distance by time. The notation is the same in both cases, so that it's easy to change representation without affecting the rest of the software.
- Command-Query Separation Principle: Queries must not modify the instance. This is not a language rule but a methodological principle. So in good Eiffel style one does not find "get" function that change something and return a result; instead there are commands (procedures) to change objects, and queries to obtain information about the object, resulting from preceding changes.
Feature names and no-overloading
An important property of Eiffel is that a class is fundamentally a mapping from feature names to features. More plainly said this means that one name, within one class, means one thing. This keeps things simple and in particular is what makes the multiple inheritance mechanism possible (see below).
Names can, of course, be reused in different classes, but in a given class if you need another feature you'll have to invent another name. This is really no limitation since the conventional kinds of overloading are, in an object-oriented perspective, applied to different classes. For example if you want to have several versions of "+"
:
a + b
fora, b: INTEGER
a + b
fora, b: REAL
a + b
fora, b: VECTOR
then in Eiffel it simply means that the three classes involved each have a feature
plus alias "+" (other: XXX): XXX
where XXX
is the given class (INTEGER
, REAL
, VECTOR )
. (See "Operator and bracket syntax, assigner commands" below.) All the usual forms of operator overloading are thus supported; in fact the mechanism (unlike in most languages) leaves considerable freedom in making up new operators, as may be needed in scientific and engineering applications. What is not possible is the kind of argument overloading where a given class has both a feature f (x: X)
and another f (y: Y)
with the same names. Meyer has argued that such overloading is useless, damages readability, and complicates the language mechanism needlessly.
Genericity
Classes can be generic, to express that they are parameterized by types. Generic parameters appear in square brackets:
class LIST ...
G is known as a "formal generic parameter". (Eiffel reserves "argument" for routines, and uses "parameter" only for generic classes.) With such a declaration G represents within the class an arbitrary type; so a function can return a value of type G, and a routine can take an argument of that type:
item: G do ... end
put (x: G) do ... end
The LIST
and LIST
are "generic derivations" of this class. Permitted combinations(with n: INTEGER
, w: WORD
, il: LIST
, wl: LIST
) are
n := il.item
wl.put (w)
INTEGER
resp. WORD
are the "actual generic parameters" in these generic derivations.
It is also possible to have constrained formal parameters, for which the actual parameter must inherit from a given class, the "constraint". For example in
class HASH_TABLE
a derivation HASH_TABLE
is valid only if STRING
inherits from HASHABLE
(as it it indeed does in typical Eiffel libraries). Within the class, having KEY
constrained by HASHABLE
means that for x: KEY
it is possible to apply to x
all the features of HASHABLE
, as in x.hash_code
.
Inheritance basics
To inherit from one or more others, a class will include a inherit
clause at the beginning:
class C inherit
A
B
... Rest of class declaration ...
The class may redefine (override) some or all of the inherited features. This must be explicitly announced at the beginning of the class through a redefine
subclause of the inheritance clause, as in
class C inherit
A
redefine f, g, h end
B
redefine u, v end
This article or section is in a state of significant expansion or restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template. If you are the editor who added this template and you are actively editing, please be sure to replace this template with {{in use}} during the active editing session. Click on the link for template parameters to use.
This article was last edited by Ideogram (talk | contribs) 18 years ago. (Update timer) |
Multiple and repeated inheritance
This article or section is in a state of significant expansion or restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template. If you are the editor who added this template and you are actively editing, please be sure to replace this template with {{in use}} during the active editing session. Click on the link for template parameters to use.
This article was last edited by Ideogram (talk | contribs) 18 years ago. (Update timer) |
Renaming
A class that inherits from one or more others gets all its features, by default under their original names. It may, however, change their names through a rename
clauses. This is required in the case of multiple inheritance if there are name clashes between inherited features; without renaming, the resulting class would violate the no-overloading principle noted above and hence would be invalid.
Tuples
Tuples types may be viewed as a simple form of class, providing only attributes and the corresponding "setter" procedure. A typical tuple type reads
TUPLE
and could be use to describe a simple notion of birth record if a class is not needed. An instance of such a tuple is simply a sequence of values with the given types, given in brackets, such as
Components of such a tuple can be accessed as if the tuple tags were attributes of a class, for example if t]
has been assigned the above tuple then t.weight]
has value 3.5.
Thanks to the notion of assigner command (see below), dot notation can also be used to assign components of such a tuple, as in
t.weight := t.weight + 0.5
The tuple tags are optional, so that it is also possible to write a tuple type as TUPLE
. (In some compilers this is the only form of tuple, as tags were introduced with the ECMA standard.)
The precise specification of e.g. TUPLE
is that it describes sequences of at least three elements, the first three being of types A
, B
, C
respectively. As a result TUPLE
conforms to (may be assigned to) TUPLE
, to TUPLE
and to TUPLE
(without parameters), the topmost tuple type to which all tuple types conform.
Agents
Eiffel provides an "agent" mechanism to wrap operations into objects. This is useful for iteration, event-driven programming, and other applications for which it is useful to pass operations around the program structure. Agents correspond lambda expressions and to closures; they make it possible to combine the object-oriented paradigm with a significant set of mechanisms available in functional programming languages.
For example, to iterate a certain action over a list, it suffices to write
my_list.do_all (agent my_action)
or, if the action is to be executed only on elements satisfying a certain condition:
my_list.do_all (agent my_action, agent my_condition)
In these examples, my_action
and my_condition
are routines. Prefixing them with agent
yields an object that represents the corresponding routine with all its properties, in particular the ability to be called with the appropriate arguments. So if a
represents that object (for example because a
is the argument to do_all
), the instruction
a.call ()
will call the original routine with the argument x
, as if we had directly called the original routine: my_action (x)
. Arguments to call
are passed as a tuple, here .
It is possible to keep some arguments to an agent open and make others closed. The open arguments are passed as arguments to call
: they are provided at the time of agent use. The closed arguments are provided at the time of agent definition. For example, if action2
has two arguments, the iteration
my_list.do_all (agent action2 (?, y)
iterates action2 (x, y)
for successive values of x
, where the second arguments remained set to y
. The question mark ?
indicates an open argument; y
is a closed argument of the agent. Note that the basic syntax agent f
is a short hand for agent f (?, ?, ...)
with all arguments open. It is also possible to make the target of an agent open through the notation {T}?
where T
is the type of the target.
The distinction between open and closed operands (operands = arguments + target) corresponds to the distinction between bound and free variables in lambda calculus. An agent expression such as action2 (?, y)
with some operands closed and some open corresponds to a version of the original operation curried on the closed operands.
The agent mechanism has been recently generalized to allow defining an agent without reference to an existing routine (such as my_action
, my_condition
, action2
), through inline agents as in
my_list.do_all
(agent (x: INTEGER)
require
positive: x > 0
do
x := x – 1
ensure
x = old x – 1
end
)
The inline agent passed here can have all the trappings of a normal routine, including precondition, postcondition, rescue clause (not used here), and a full signature. This avoids defining routines when all that's needed is a computation to be wrapped in an agent. This is useful in particular for contracts, as in an invariant clause that expresses that all elements of a list are positive:
my_list.for_all (agent (x: INTEGER): BOOLEAN do Result := (x > 0) end)
The current agent mechanism leaves a possibility of run-time type error (if a routine with n arguments is passed to an agent expecting m arguments with m < n). This can be avoided by a run-time check through the precondition valid_arguments
of call
. Several proposals for a purely static correction of this problem are available, including a language change proposal by Ribet et al. .
Once routines
A routine can be declared "once" (with the keyword once
replacing the more common do
) to indicate that it will only be executed on the first call. Subsequent calls have no further effect; in the case of a function, they return the same value as the first, for example a reference to the same object.
"Once" functions serve in particular to provide shared objects; the first call will create the object, subsequent ones will return the reference to that object. The typical scheme is
shared_object: SOME_TYPE
do
create Result.make (args) -- This creates the object and returns a reference to it through Result
end
While the reference remains the same, later calls of the form shared_object.do_something
can change the content of the object.
"Once" procedures can take care of initialization: several clients of a certain libraries can include a call to the initialization procedure, but only the first such call to happen will actually have an effect. The goal is to achieve decentralized initialization, avoiding the need for an initialization module (which could damage the modular structure of the program).
The ECMA specification allows variants of "once" (qualified by a keyword in parentheses, e.g. once (THREAD)
: once per process, once per thread, once per object. This is not, however, fully implemented yet by current compilers (typically, only PROCESS and THREAD).
Conversions
Eiffel provides a mechanism to allow conversions between various types. The mechanisms coexists with inheritance and complements it. To avoid any confusion between the two mechanisms, the design enforces the following principle:
(Conversion principle) A type may not both conform and convert to another
For example NEWSPAPER
may conform to to PUBLICATION
, but INTEGER
converts to REAL
(and does not inherit from it).
The conversion mechanism simply generalizes the ad hoc conversion rules (such as indeed between INTEGER
and REAL
) that exist in most programming languages, making them applicable to any type as long as the above principle is observed. For example a REAL
class may be declared to convert to REAL
; this makes it possible to create a string from a date simply through
my_string := my_date
as a shortcut for using an explicit object creation with a conversion procedure:
create my_string.make_from_date (my_date)
To make the first form possible as a synonym for the first, it suffices to list the creation procedure (constructor) make_from_date
in a convert
clause at the beginning of the class.
As another example, if there is such a conversion procedure listed from TUPLE ]
, then one can directly assign a tuple to a date, causing the appropriate conversion, as in
Bastille_day :=
Exception handling
This article or section is in a state of significant expansion or restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template. If you are the editor who added this template and you are actively editing, please be sure to replace this template with {{in use}} during the active editing session. Click on the link for template parameters to use.
This article was last edited by Ideogram (talk | contribs) 18 years ago. (Update timer) |
Operator and bracket syntax, assigner commands
Eiffel's view of computation is completely object-oriented in the sense that every operation is relative to an object, the "target". So for example an addition
a + b
is conceptually understood as if it were a function call
a.plus (b)
with target a
, feature plus
and argument b
.
Of course is the conventional syntax and usually preferred. Operator syntax makes it possible to use either form by declaring the feature (for example in INTEGER
, but this applies to other basic classes and can be used in any other for which such an operator appropriate):
plus alias "+" (other: INTEGER): INTEGER
... Normal function declaration...
end
The range of operators that can be used as "alias" is quite broad; they include predefined operators such as "+" but also "free operators" made of non-alphanumeric symbols. This makes it possible to design special infix and prefix notations, for example in mathematics and physics applications.
Every class may in addition have one function aliased to "", the "bracket" operator, allowing the notation a
as a synonym for a.f (i, ...)
where f
is the chosen function. This is particularly useful for container structures such as arrays, hash tables, lists etc. For example access to an element of a hash table with string keys can be written
number := phone_book
"Assigner commands" are a companion mechanism designed in the same spirit of allowing well-established, convenient notation reinterpreted in the framework of object-oriented programming. Assigner commands allow assignment-like syntax to call "setter" procedures. An assignment proper can never be of the form a.x := v]
as this violates information hiding; you have to go for a setter command (procedure). For example the hash table class can have the function and the procedure
item alias "" (key: STRING): ELEMENT
-- The element of key key -- ("Getter" query) do ... end
put(e: ELEMENT; key: STRING): ELEMENT -- Insert the element e, associating it with the key key. -- ("Setter" command) do ... end
Then to insert an element you have to use an explicit call to the setter command:
phone_book.put (New_person, "JILL SMITH")
It is possible to write this equivalently as
phone_book := New_person
(in the same way that phone_book
is a synonym for number := phone_book.item ("JILL SMITH")
), provided the declaration of item
now starts (replacement for ) with
item alias "" (key: STRING): ELEMENT assign put
This declares put
as the assigner command associated with item
and, combined with the bracket alias, makes legal and equivalent to . (It could also be written, without taking advantage of the bracket, as phone_book.item ("JILL SMITH") := New_person
.
Lexical and syntax properties
Eiffel is not case-sensitive. The tokens make
, maKe
and MAKE
all denote the same identifier. See, however, the "style rules" below.
Comments are introduced by --
(two consecutive dashes) and extend to the end of the line.
The semicolon, as instruction separator, is optional. Most of the time the semicolon is just omitted, except to separate multiple instructions on a line. This results in less clutter on the program page.
There is no nesting of feature and class declarations. As a result the structure of an Eiffel class is simple: some class-level clauses (inheritance, invariant) and a succession of feature declarations, all at the same level.
It is customary to group features into separate "feature clauses" for more readability, with a standard set of basic feature tags appearing in a standard order, for example:
class HASH_TABLE inherit
TABLE
feature -- Initialization
... Declarations of initialization commands (creation procedures/constructors) ...
feature -- Access
... Declarations of non-boolean queries on the object state, e.g. item ...
feature -- Status report
... Declarations of boolean queries on the object state, e.g. is_empty ...
feature -- Element change
... Declarations of commands that change the structure, e.g. put ...
etc.
end
In contrast to most curly bracket programming languages, Eiffel makes a clear distinction between expressions and instructions. This is in line with the Command-Query Separation principle of the Eiffel method.
Style rules
Eiffel is distinguished by strong style rules, designed to enforce a consistent look-and-feel.
While the language is case-insensitive, the style standards prescribe the use of all-capitals for class names (LIST
), all-lower-case for feature names (make
), and initial capitals for constants (Avogadro
).
The recommended style also suggests underscore to separate components of a multi-word identifier, as in average_temperature
.
The specification of Eiffel includes guidelines for displaying software texts in typeset formats: keywords in bold, user-defined identifiers and constants are shown in italics
, comments, operators, and punctuation marks in roman
, with program text in blue
as in the present article to distinguish it from explanatory text.
Basic instructions
Eiffel has only six basic executable instructions:
- assignment
- object creation
- routine call
- conditional
- iteration
- choice (case)
Unlike many object-oriented languages, but like Smalltalk, Eiffel does not permit an assignment into fields of other objects, as this violates the principles of information hiding and data abstraction. The assignment instruction can only change the value of a field of the current object, or a local variable of the current routine. All changes to other objects must be accomplished by calls to features of that object.
The loop instruction includes a from clause that takes care of loop initialization. The programmer must express the stepping as part of the loop. For example:
from i := 0 until i >= 10 loop
my_array.put (0, i)
i := i + 1
end
The example above also illustrates that Eiffel treats arrays simply as instances of the class ARRAY, providing access in the form of routine calls, in line with object-oriented ideas. Eiffel compilers optimize this access.
Eiffel's control structures closely follow the principles of structured programming; every block is one-entry-one exit.
Interfaces to other tools and languages
Eiffel is a purely object-oriented language but provides an open architecture for interfacing with "external" software in any other programming language.
It is possible for example to program machine- and operating-system level operations in C. Eiffel provides a straightforward interface to C routines, including support for "inline C" (writing the body of an Eiffel routine in C, typically for short machine-level operations).
Although there is no direct connection between Eiffel and C, all of the current Eiffel compilers except one (Visual Eiffel) output C source code as an intermediate language, to submit to a C compiler, for optimizing and portability. On .NET, the EiffelStudio compiler directly generates CIL (Common Intermediate Language) code for the .NET virtual machine. The SmartEiffel compiler can also output Java bytecode.
Background
Eiffel was originally developed by Eiffel Software, a company founded by Bertrand Meyer (originally called Interactive Software Engineering Inc. or ISE). Eiffel closely follows Dr. Meyer's work in Object Oriented Software Construction, Second Edition. Eiffel differs from most popular languages in several ways.
The goal of the language, libraries, and programing methods is to create reliable, reusable software modules. It supports multiple inheritance, genericity, polymorphism, encapsulation, type-safe conversions, and parameter covariance. Its most important contribution to software engineering is Design by contract (DbC), in which assertions, preconditions, postconditions, and class invariants are used to assist in assuring program correctness without sacrificing efficiency.
Eiffel also offers multiple class inheritance. Many people (such as the designers of Java) have objections to multiple inheritance. The Eiffel implementation of multiple inheritance, in the opinion of its supporters, successfully meets these objections.
Eiffel's design is closely based on Object-Oriented Programming (OOP) theory, with less influence from other paradigms or support for legacy code. The language has formal support for abstract data types. In accordance with Self Documentation, a software text should be able to reproduce its design documentation from the text itself. Eiffel accomplishes this by using a formalized implementation of the Abstract Data Type.
EiffelStudio, an integrated development environment for Eiffel available under both an open source and a commercial licenses, offers an object-oriented environment for software engineering, using some innovative user-interface techniques such as Pick-And-Drop. There are two alternative, also open source implementations, SmartEiffel - the GNU implementation, based on an older version of the language, and Visual Eiffel, which provides a more "traditional" interface. So does EiffelEnvision, a plugin for Microsoft Visual Studio which allows users to edit, compile, and debug Eiffel apps from within the Microsoft Visual Studio IDE. EiffelStudio and EiffelEnvision are only free for non-commercial use, though.
Originally, the language Sather was based on Eiffel, but it has diverged, and now includes several functional programming features.
Specifications and standards
The Eiffel language definition is an international standard of ISO, the International Standards Organization. The standard was developed by ECMA International and its first version approved by ECMA on 21 June 2005 as ECMA standard 367, Eiffel: Analysis, Design and Implementation Language. The second edition was adopted by ECMA in June 2006 and in the same month by ISO. Its text can be found, and used free of charge, on the ECMA site. The ISO version, standard ISO/IEC DIS 25436, has different formating but its text is identical.
Eiffel Software and Gobo have committed to implementing the standard; Eiffel Software's EiffelStudio 5.7 implements some of the major new mechanisms, in particular inline agents, assigner commands, bracket notation. The SmartEiffel team has turned away from this standard to create its own version of the language, which they believe to be closer to the original style of Eiffel. Object Tools has not to date expressed a position.
The standard cites the following as earlier Eiffel Language specifications:
- Bertrand Meyer: Eiffel: The Language, Prentice Hall, second printing, 1992 (first printing: 1991)
- Bertrand Meyer: Standard Eiffel (revision of preceding entry), ongoing, 1997-present, at Bertrand Meyer's ETL3 page, and
- Bertrand Meyer: Object-Oriented Software Construction, Prentice Hall: first edition, 1988; second edition, 1997.
The ETL3 page requires a password for access which can be found at Bertrand Meyer's Home Page under Work in progress
Differences between SmartEiffel and other implementations
- SmartEiffel is currently unable to compile the open-source EiffelBase library from Eiffel Software.
- SmartEiffel is case-sensitive.
A "Hello World" class
class
HELLO_WORLD
create
make
feature
make is
do
io.put_string ("Hello, world!")
io.put_new_line
end
end
References
- Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October-November 2001, available online
- Philippe Ribet, Cyril Adrian, Olivier Zendra, Dominique Colnet: Conformance of agents in the Eiffel language, in Journal of Object Technology, vol. 3, no. 4, April 2004, Special issue: TOOLS USA 2003, pp. 125-143. Available on line from the JOT article page
- ECMA International: Standard ECMA-367 —Eiffel: Analysis, Design and Programming Language 2nd edition (June 2006); available online at www.ecma-international.org/publications/standards/Ecma-367.htm
- Object-Oriented Software Construction, Second Edition, by Bertrand Meyer, Prentice Hall, 1997, ISBN 0-13-629155-4 (see its Misplaced Pages article); contains a detailed treatment of the concepts and theory of object technology, which led to the design of Eiffel. Available in several languages.
See also
- Object-Oriented Software Construction
- EiffelStudio
- Apple Media Tool which includes the Eiffel-based Apple Media Language
External links
- Eiffel Software's Open Source initiative
- Eiffel Software web site of the company that introduced Eiffel, was Interactive Software Engineering (ISE).
- Eiffel tutorial (100 pages) by Bertrand Meyer (HTML, PDF)
- Eiffel standard, revision 2 (2006); this is the ECMA standard, with free access, its text identical to that of the ISO standard.
- SmartEiffel fairly complete Eiffel compiler, released under GNU GPL license, was SmallEiffel, not ECMA standard compliant.
- Visual Eiffel an open source implementation of Eiffel creating native code for X86 systems (Windows, Linux)
- NICE Nonprofit International Consortium for Eiffel.
- eiffelzone.com Includes a comprehensive Eiffel Software Directory
- Cetus Eiffel Page
- Eiffel for .Net
- Eiffel: the Language subset