Revision as of 16:21, 22 August 2006 editLulu of the Lotus-Eaters (talk | contribs)Extended confirmed users21,790 edits This is very bad behavior, Bertrand: Contributions are released as GFDL, they ARE NOT "yours" in any copyright or ethical sense← Previous edit | Latest revision as of 06:47, 29 November 2024 edit undoJerryobject (talk | contribs)Extended confirmed users15,332 edits Parameters: adds, fills, move. Mea culpa: corrected misplaced date from my last edit of this article. | ||
(674 intermediate revisions by more than 100 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Object-oriented programming language}} | |||
{{Infobox programming language | {{Infobox programming language | ||
|name = Eiffel | | name = Eiffel | ||
|logo = | | logo = Eiffel logo.svg | ||
| logo caption = Eiffel logo | |||
|paradigm = ] | |||
| paradigm = ]: ], ], ], ] | |||
|year = ] | |||
|designer = ] | | designer = ] | ||
|developer = |
| developer = Eiffel Software | ||
| released = {{Start date and age|1986}}<ref>{{cite web |title=Eiffel in a Nutshell |url=https://archive.eiffel.com/eiffel/nutshell.html |date=1985–2012 |website=Eiffel Software |language=en |access-date=29 November 2024}}</ref> | |||
|latest release version = 4.2 | |||
| latest release version = ] 24.05<ref>{{cite web |title=EiffelStudio 24.05 is available! |url=https://www.eiffel.org/blog/eiffelstudio_24_05 |date=14 June 2024 |website=Eiffel.org |access-date=29 November 2024}}</ref> | |||
|latest release date = ], ] | |||
| latest release date = {{Start date and age|2024|06|14|df=y}} | |||
|typing = ], ] | |||
| typing = ] | |||
|implementations = ], ], ] | |||
| implementations = ], ], ], ], Gobo Eiffel, "The Eiffel Compiler" tecomp | |||
|dialects = | |||
| |
| programming language = Eiffel | ||
| platform = ] | |||
|influenced = ], ], ], ] | |||
| operating system = ], ], ], ], ], ] | |||
| license = dual and enterprise | |||
| file ext = <code>.e</code> | |||
| website = {{URL|eiffel.org}} | |||
| dialects = | |||
| influenced by = ], ], ] | |||
| influenced = ], ], ], ], ], ], ],<ref name="nov2pro">{{cite book |last1=Cooper |first1=Peter |year=2009 |title=Beginning Ruby: From Novice to Professional |edition=2nd |series=Beginning from Novice to Professional |publisher=APress |location=Berkeley |isbn=978-1-4302-2363-4 |page=101 |quote=To a lesser extent, Python, LISP, Eiffel, Ada, and C++ have also influenced Ruby.}}</ref> ], ] | |||
}} | }} | ||
'''Eiffel''' is an ] ] designed by ] (an object-orientation proponent and author of '']'') and Eiffel Software. Meyer conceived the language in 1985 with the goal of increasing the reliability of commercial software development.<ref>{{cite web |title=Eiffel – the Language |url=http://www.berenddeboer.net/eiffel/archive/halstenbach_eiffel_history.html |access-date=6 July 2016 |website=berenddeboer.net}}</ref> The first version was released in 1986. In 2005, the ] (ISO) released a ] for Eiffel. | |||
'''Eiffel''' is an ]-standardized ] ], based on a conscious design methodology, intended for the production of quality software with a particular emphasis on extendibility, reusability, reliability and programmer productivity. | |||
The design of the language is closely connected with the Eiffel programming method. Both are based on a set of principles, including ], ], the ], the ], the ], and ]. | |||
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. | |||
Many concepts initially introduced by Eiffel were later added into ], ], and other languages.<ref>{{Cite book |last1=Meyer |first1=Bertrand |author1-link=Bertrand Meyer |date=2009-08-28 |url=https://books.google.com/books?id=6yupzA8JZjQC&dq=Many+concepts+initially+introduced+by+Eiffel+later+found+their+way+into+Java,+C&pg=PR37 |title=Touch of Class: Learning to Program Well with Objects and Contracts |publisher=Springer Science & Business Media |isbn=978-3-540-92144-8 |language=en}}</ref> New language design ideas, particularly through the ]/] standardization process, continue to be incorporated into the Eiffel language. | |||
The language design is closely connected with the method, based on a set of principles: ], ], Uniform access principle, Single choice principle, Open-closed principle, Option-Operand separation and others. | |||
==Characteristics== | |||
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 ]/] standardization process. | |||
The key characteristics of the Eiffel language include: | |||
* An object-oriented program structure in which a class serves as the basic unit of decomposition.<ref>{{cite web | title=Programming Languages - Eiffel | website=Department of Computer Science, Virginia Tech | url=https://courses.cs.vt.edu/~cs3304/Spring02/lectures/lect12.pdf | access-date=25 March 2023}}</ref> | |||
==Overview== | |||
* ] tightly integrated with other language constructs. | |||
* Automatic memory management, typically implemented by ].<ref>{{cite web | author=Carl Friess|title=Eiffel Syntax Guide | website=Eiffel Syntax Guide | url=https://eiffel-guide.com/ | access-date=25 March 2023}}</ref> | |||
* ], including ], ], ], "select", , and other mechanisms intended to make inheritance safe. | |||
* Constrained and unconstrained ]<ref name="Claus">{{cite web | author=Claus Brabrand |title=The E I F F E L Programming Language | website=IT University of Copenhagen | url=http://www.itu.dk/people/brabrand/GSD-2013/Eiffel.pdf | access-date=25 March 2023}}</ref> | |||
* A uniform ] handling both value and reference semantics in which all types, including basic types such as INTEGER, are class-based. | |||
* ] | |||
* ], or static protection against calls on null references, through the attached-types mechanism. | |||
* Agents, or objects that wrap computations, closely connected with ]s and ]. | |||
* ''Once'' routines, or routines evaluated only once, for object sharing and decentralized initialization. | |||
* Keyword-based syntax in the ]/] tradition but separator-free, insofar as semicolons are optional, with operator syntax available for routines. | |||
* Case insensitivity | |||
* Simple Concurrent Object-Oriented Programming (]) facilitates creation of multiple, concurrently active execution vehicles at a level of abstraction above the specific details of these vehicles (e.g. multiple threads without specific mutex management). | |||
==Design goals== | |||
Key characteristics of the language, explained in more detail below, include: | |||
Eiffel emphasizes declarative statements over procedural code and attempts to eliminate the need for bookkeeping instructions. | |||
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, extensible, reusable, and reliable answers to computing problems. Compilers for computer programs written in Eiffel provide extensive optimization techniques, such as automatic in-lining, that relieve the programmer of part of the optimization burden. | |||
* 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. | |||
* ]. | |||
* Support for automatic memory management, typically implemented by ]). | |||
* Central role of ] 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. | |||
* ], constrained and unconstrained. | |||
* "Agents" (objects wrapping computations, closely connected with ]s and ]. | |||
* "Once" routines (evaluated only the first time around), for object sharing and decentralized initialization. | |||
* Keyword-based syntax ]/] tradition but separator-free (semicolon is optional); operator syntax available for routines. | |||
=== |
===Background=== | ||
Eiffel was originally developed by Eiffel Software, a company founded by ]. '']'' contains a detailed treatment of the concepts and theory of the object technology that led to Eiffel's design.<ref>''Object-Oriented Software Construction'', Second Edition, by ], Prentice Hall, 1997, {{ISBN|0-13-629155-4}}</ref> | |||
The Eiffel language aims to promote clear and elegant programming. Eiffel emphasizes declarative statements over procedural code, and eliminates the need for bookkeeping instructions. | |||
The design goal behind the Eiffel language, libraries, and programming methods is to enable programmers to create reliable, reusable software modules. Eiffel supports ], ], ], ], type-safe conversions, and ]. Eiffel's most important contribution to ] is ] (DbC), in which ], ]s, ]s, and ]s are employed to help ensure program correctness without sacrificing efficiency. | |||
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's design is based on object-oriented programming theory, with only minor influence of other paradigms or concern for support of legacy code. Eiffel formally supports ]s. Under Eiffel's design, a software text should be able to reproduce its design documentation from the text itself, using a formalized implementation of the "Abstract Data Type". | |||
==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.) | |||
===Implementations and environments=== | |||
The concepts of ] are central to Eiffel. The mechanisms are tightly integrated with the language. The basic constructs are: | |||
] is an ] available under either an ] or a commercial license. It offers an object-oriented environment for ]. EiffelEnvision is a plug-in for ] that allows users to edit, compile, and debug Eiffel projects from within the Microsoft Visual Studio IDE. Five other ] implementations are available: "The Eiffel Compiler" tecomp; Gobo Eiffel; ], the GNU implementation, based on an older version of the language; ], based on the SmartEiffel compiler; and ]. | |||
Several other programming languages incorporate elements first introduced in Eiffel. ], for example, was originally based on Eiffel but has since diverged, and now includes several ] features. The interactive-teaching language Blue, forerunner of ], is also Eiffel-based. The ] includes an Eiffel-based Apple Media Language. | |||
*Routine precondition | |||
*Routine postcondition | |||
*Class invariant | |||
===Specifications and standards=== | |||
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. | |||
The Eiffel language definition is an international standard of the ]. The standard was developed by ], which first approved the standard on 21 June 2005 as Standard ECMA-367, Eiffel: Analysis, Design and Programming Language. In June 2006, ECMA and ISO adopted the second version. In November 2006, ISO first published that version. The standard can be found and used free of charge on the ECMA site.<ref>ECMA International: Standard ECMA-367{{snd}} Eiffel: Analysis, Design and Programming Language 2nd edition (June 2006); available online at </ref> The ISO version<ref>International Organization for Standardization: Standard ISO/IEC DIS 25436, available online at </ref> is identical in all respects except formatting. | |||
Eiffel Software, "The Eiffel Compiler" tecomp and Eiffel-library-developer Gobo have committed to implementing the standard; Eiffel Software's EiffelStudio 6.1 and "The Eiffel Compiler" tecomp implement some of the major new mechanisms—in particular, inline agents, assigner commands, bracket notation, non-conforming inheritance, and attached types. The ] 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 disclosed whether future versions of its Eiffel compiler will comply with the standard. ] implements a dialect somewhere in between the ] language and the standard. | |||
As defined in the Design by Contract methodology, contracts guide redefinition of features in inheritance. Specifically, in a redefinition: | |||
The standard cites the following, predecessor Eiffel-language specifications: | |||
*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>. | |||
* 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. | |||
* Bertrand Meyer: ''Touch of Class: Learning to Program Well with Objects and Contracts'', Springer-Verlag, 2009 {{ISBN|978-3-540-92144-8}} lxiv + 876 pages Full-color printing, numerous color photographs | |||
The current version of the standard from June 2006 contains some inconsistencies (e.g. covariant redefinitions){{Citation needed|date=October 2010}}. The ECMA committee has not yet announced any timeline and direction on how to resolve the inconsistencies. | |||
*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>. | |||
==Syntax and semantics== | |||
==Other language mechanisms== | |||
===Overall structure=== | ===Overall structure=== | ||
An Eiffel "system" or "program" is a collection of ''classes''. Above the level of classes, Eiffel defines ''cluster'', which is essentially a group of classes, and possibly of ''subclusters'' (nested clusters). Clusters are not a syntactic ], but rather a standard organizational convention. Typically an Eiffel program will be organized with each class in a separate file, and each cluster in a directory containing class files. In this organization, subclusters are subdirectories. For example, under standard organizational and casing conventions, <code>x.e</code> might be the name of a file that defines a class called X. | |||
An Eiffel "'''system'''" (or "program") is a collection of '''classes'''. The class is the major unit of decomposition. | |||
A class contains ''features'', which are similar to "routines", "members", "attributes" or "methods" in other object-oriented programming languages. A class also defines its invariants, and contains other properties, such as a "notes" section for documentation and metadata. Eiffel's standard data types, such as <code>INTEGER</code>, <code>STRING</code> and <code>ARRAY</code>, are all themselves classes. | |||
Every system must have a class designated as "root", with one of its creation procedures designated as "root procedure". Executing a system consists of creating an instance of the root class and executing its root procedure. Generally, doing so creates new objects, calls new features, and so on. | |||
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. | |||
Eiffel has five basic executable instructions: assignment, object creation, routine call, condition, and iteration. Eiffel's control structures are strict in enforcing ]: every block has exactly one entry and exactly one exit. | |||
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. | |||
====Scoping==== | |||
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.) | |||
Unlike many object-oriented languages, but like ], Eiffel does not permit any assignment into attributes of objects, except within the features of an object, which is the practical application of the principle of ] or data abstraction, requiring formal interfaces for data mutation. To put it in the language of other object-oriented programming languages, all Eiffel attributes are "protected", and "setters" are needed for client objects to modify values. An upshot of this is that "setters" can and normally do, implement the invariants for which Eiffel provides syntax. | |||
While Eiffel does not allow direct access to the features of a class by a client of the class, it does allow for the definition of an "assigner command", such as: | |||
===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: | |||
<syntaxhighlight lang="eiffel"> | |||
*Queries, which give information about an instance. | |||
some_attribute: SOME_TYPE assign set_some_attribute | |||
*Commands, which modify an instance. | |||
set_some_attribute (v: VALUE_TYPE) | |||
-- Set value of some_attribute to `v'. | |||
do | |||
some_attribute := v | |||
end | |||
</syntaxhighlight> | |||
While a slight bow to the overall developer community to allow something looking like direct access (e.g. thereby breaking the Information Hiding Principle), the practice is dangerous as it hides or obfuscates the reality of a "setter" being used. In practice, it is better to redirect the call to a setter rather than implying a direct access to a feature like <code>some_attribute</code> as in the example code above.{{Citation needed|reason=Working fine in Delphi (Object Pascal) for 25 years. In Eiffel, if a setter is the only way to set an attribute, this must obviously be what is going on. How is that 'obfuscated'?|date=March 2021}} | |||
This distinction is important to the Eiffel method. In particular: | |||
Unlike other languages, having notions of "public", "protected", "private" and so on, Eiffel uses an exporting technology to more precisely control the scoping between client and supplier classes. Feature visibility is checked statically at compile-time. For example, (below), the "{NONE}" is similar to "protected" in other languages. Scope applied this way to a "feature set" (e.g. everything below the 'feature' keyword to either the next feature set keyword or the end of the class) can be changed in descendant classes using the "export" keyword. | |||
*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. | |||
<syntaxhighlight lang="eiffel"> | |||
*]: 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 {NONE} -- Initialization | |||
default_create | |||
-- Initialize a new `zero' decimal instance. | |||
do | |||
make_zero | |||
end | |||
</syntaxhighlight> | |||
Alternatively, the lack of a {x} export declaration implies {ANY} and is similar to the "public" scoping of other languages. | |||
===Feature names and no-overloading=== | |||
<syntaxhighlight lang="eiffel"> | |||
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). | |||
feature -- Constants | |||
</syntaxhighlight> | |||
Finally, scoping can be selectively and precisely controlled to any class in the Eiffel project universe, such as: | |||
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>: | |||
<syntaxhighlight lang="eiffel"> | |||
feature {DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER} -- Access | |||
</syntaxhighlight> | |||
Here, the compiler will allow only the classes listed between the curly braces to access the features within the feature group (e.g. {{mono|DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER}}). | |||
<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> | |||
===="Hello, world!"==== | |||
then in Eiffel it simply means that the three classes involved each have a feature | |||
A programming language's look and feel is often conveyed using a ] program. Such a program written in Eiffel might be: | |||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''plus'' '''alias''' "+" (''other'': ''XXX''): ''XXX''</font></code> | |||
class | |||
HELLO_WORLD | |||
create | |||
make | |||
feature | |||
make | |||
do | |||
print ("Hello, world!%N") | |||
end | |||
end | |||
</syntaxhighlight> | |||
This program contains the class <code>HELLO_WORLD</code>. The constructor (create routine) for the class, named <code>make</code>, invokes the <code>print</code> system library routine to write a <code>"Hello,</code> <code>world!"</code> message to the output. | |||
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. | |||
===Design by contract=== | |||
{{Further|Design by contract}} | |||
The concept of Design by Contract is central to Eiffel. The contracts assert what must be true before a routine is executed (precondition) and what must hold to be true after the routine finishes (post-condition). Class Invariant contracts define what assertions must hold true both before and after any feature of a class is accessed (both routines and attributes). Moreover, contracts codify into executable code developer and designers assumptions about the operating environment of the features of a class or the class as a whole by means of the invariant. | |||
The Eiffel compiler is designed to include the feature and class contracts in various levels. EiffelStudio, for example, executes all feature and class contracts during execution in the "Workbench mode." When an executable is created, the compiler is instructed by way of the project settings file (e.g. ECF file) to either include or exclude any set of contracts. Thus, an executable file can be compiled to either include or exclude any level of contract, thereby bringing along continuous levels of unit and integration testing. Moreover, contracts can be continually and methodically exercised by way of the Auto-Test feature found in EiffelStudio. | |||
The Design by Contract mechanisms are tightly integrated with the language and guide redefinition of features in inheritance: | |||
* Routine precondition: The precondition may only be weakened by inheritance; any call that meets the requirements of the ancestor meets those of the descendant. | |||
* Routine postcondition: The postcondition can only be strengthened by inheritance; any result guaranteed by the ancestor is still provided by the descendant. | |||
* Class invariant: Conditions that must hold true after the object's creation and after any call to an exported class routine. Because the invariant is checked so often, it makes it simultaneously the most expensive and most powerful form of condition or contract. | |||
In addition, the language supports a "check instruction" (a kind of "assert"), loop invariants, and loop variants (which guarantee loop termination). | |||
===Void-safe capability=== | |||
{{Further|Void safety}} | |||
Void-safe ability, like static typing, is another facility for improving software quality. Void-safe software is protected from ] errors caused by calls to ], and therefore will be more reliable than software in which calls to void targets can occur. The analogy to static typing is a useful one. Void-safe ability can be seen as an extension to the type system, or a step beyond static typing, because the mechanism for ensuring void safety is integrated into the type system. | |||
The guard against void target calls can be seen by way of the notion of attachment and (by extension) detachment (e.g. detachable keyword). The void-safe facility can be seen in a short re-work of the example code used above: | |||
<syntaxhighlight lang="eiffel"> | |||
some_attribute: detachable SOME_TYPE | |||
use_some_attribute | |||
-- Set value of some_attribute to `v'. | |||
do | |||
if attached some_attribute as l_attribute then | |||
do_something (l_attribute) | |||
end | |||
end | |||
do_something (a_value: SOME_TYPE) | |||
-- Do something with `a_value'. | |||
do | |||
... doing something with `a_value' ... | |||
end | |||
</syntaxhighlight> | |||
The code example above shows how the compiler can statically address the reliability of whether <code>some_attribute</code> will be attached or detached at the point it is used. Notably, the <code>attached</code> keyword allows for an "attachment local" (e.g. <code>l_attribute</code>), which is scoped to only the block of code enclosed by the if-statement construct. Thus, within this small block of code, the local variable (e.g. <code>l_attribute</code>) can be statically guaranteed to be non-void (i.e. void safe). | |||
===Features: commands and queries=== | |||
The primary characteristic of a class is that it defines a set of features: as a class represents a set of run-time objects, or "instances", a feature is an operation on these objects. There are two kinds of features: queries and commands. A query provides information about an instance. A command modifies an instance. | |||
The command-query distinction is important to the Eiffel method. In particular: | |||
* ]: from the point of view of a software client making a call to a class feature, whether a query is an attribute (field value) or a function (computed value) should not make any difference. For example, <code>a_vehicle.speed</code> could be an attribute accessed on the object <code>a_vehicle</code>, or it could be computed by a function that divides distance by time. The notation is the same in both cases, so that it is easy to change the class's implementation without affecting client 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" functions 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. | |||
===Overloading=== | |||
Eiffel does not allow argument ]. Each feature name within a class always maps to a specific feature within the class. One name, within one class, means one thing. This design choice helps the readability of classes, by avoiding a cause of ambiguity about which routine will be invoked by a call. It also simplifies the language mechanism; in particular, this is what makes Eiffel's multiple inheritance mechanism possible.<ref>Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October–November 2001, available </ref> | |||
Names can, of course, be reused in different classes. For example, the feature {{mono|plus}} (along with its infix ] {{mono|"+"}}) is defined in several classes: {{mono|INTEGER}}, {{mono|REAL}}, {{mono|STRING}}, etc. | |||
===Genericity=== | ===Genericity=== | ||
{{See also|Generic programming#Genericity in Eiffel}} | |||
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> | |||
A generic class is a class that varies by type (e.g. LIST , a list of phone numbers; ACCOUNT , allowing for ACCOUNT and ACCOUNT , etc.). Classes can be generic, to express that they are parameterized by types. Generic parameters appear in square brackets: | |||
<syntaxhighlight lang="eiffel"> | |||
class LIST ... | |||
</syntaxhighlight> | |||
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: | 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: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color="blue">''item'': ''G'' '''do''' ... '''end''' | |||
item: G do ... end | |||
put (x: G) do ... end | |||
</syntaxhighlight> | |||
The <code> |
The <code>LIST </code> and <code>LIST </code> are "generic derivations" of this class. Permitted combinations (with <code>n: INTEGER</code>, <code>w: WORD</code>, <code>il: LIST </code>, <code>wl: LIST </code>) are: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color="blue">''n'' := ''il''.''item'' | |||
n := il.item | |||
''wl''.''put'' (''w'')</font></code> | |||
wl.put (w) | |||
</syntaxhighlight> | |||
<code> |
<code>INTEGER</code> and <code>WORD</code> are the "actual generic parameters" in these generic derivations. | ||
It is also possible to have |
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 | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color="blue">'''class''' ''HASH_TABLE'' </font></code> | |||
class HASH_TABLE | |||
</syntaxhighlight> | |||
a derivation <code> |
a derivation <code>HASH_TABLE </code> is valid only if <code>STRING</code> inherits from <code>HASHABLE</code> (as it indeed does in typical Eiffel libraries). Within the class, having <code>KEY</code> constrained by <code>HASHABLE</code> means that for <code>x: KEY</code> it is possible to apply to <code>x</code> all the features of <code>HASHABLE</code>, as in <code>x.hash_code</code>. | ||
===Inheritance basics=== | ===Inheritance basics=== | ||
To inherit from one or more others, a class will include an <code>inherit</code> clause at the beginning: | |||
<syntaxhighlight lang="eiffel"> | |||
To inherit from one or more others, a class will include a <code><font color=blue>'''inherit'''</font></code> clause at the beginning: | |||
class C inherit | |||
A | |||
B | |||
-- ... Rest of class declaration ... | |||
<code><font color=blue>'''class''' ''C'' '''inherit''' | |||
</syntaxhighlight> | |||
''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> |
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>redefine</code> subclause of the inheritance clause, as in | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>'''class''' ''C'' '''inherit''' | |||
class C inherit | |||
''A'' | |||
A | |||
'''redefine''' ''f'', ''g'', ''h'' '''end''' | |||
|
redefine f, g, h end | ||
B | |||
'''redefine''' ''u'', ''v'' '''end'''</font></code> | |||
redefine u, v end | |||
</syntaxhighlight> | |||
See<ref>{{cite web|url=http://archive.eiffel.com/doc/online/eiffel50/intro/language/tutorial-10.html |title=9 INHERITANCE |publisher=Archive.eiffel.com |date=1997-03-23 |access-date=2013-07-08}}</ref> for a complete discussion of Eiffel inheritance. | |||
{{ Underconstruction }} | |||
=== |
===Deferred classes and features=== | ||
Classes may be defined with <code>deferred class</code> rather than with <code>class</code> to indicate that the class may not be directly instantiated. Non-instantiatable classes are called ]es in some other object-oriented programming languages. In Eiffel parlance, only an "effective" class can be instantiated (it may be a descendant of a deferred class). A feature can also be deferred by using the <code>deferred</code> keyword in place of a <code>do</code> clause. If a class has any deferred features it must be declared as deferred; however, a class with no deferred features may nonetheless itself be deferred. | |||
{{ Underconstruction }} | |||
Deferred classes play some of the same role as ] in languages such as Java, though many object-oriented programming theorists believe interfaces are themselves largely an answer to Java's lack of multiple inheritance (which Eiffel has).<ref>{{cite web|url=http://www.artima.com/intv/abcs.html |title=Multiple Inheritance and Interfaces |publisher=Artima.com |date=2002-12-16 |access-date=2013-07-08}}</ref><ref>{{cite web|url=https://c2.com/cgi/wiki?MultipleInheritanceIsNotEvil |title=Multiple Inheritance Is Not Evil |publisher=C2.com |date=2007-04-28 |access-date=2013-07-08}}</ref> | |||
===Renaming=== | ===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 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 <code>rename</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=== | ||
Tuples types may be viewed as a simple form of class, providing only attributes and the corresponding "setter" procedure. A typical tuple type reads | Tuples types may be viewed as a simple form of class, providing only attributes and the corresponding "setter" procedure. A typical tuple type reads | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''TUPLE'' </font></code> | |||
TUPLE | |||
</syntaxhighlight> | |||
and could be |
and could be used 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 | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue></font></code> | |||
</syntaxhighlight> | |||
Components of such a tuple can be accessed as if the tuple tags were attributes of a class, for example if <code> |
Components of such a tuple can be accessed as if the tuple tags were attributes of a class, for example if <code>t</code> has been assigned the above tuple then <code>t.weight</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 | Thanks to the notion of assigner command (see below), dot notation can also be used to assign components of such a tuple, as in | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''t''.''weight'' := ''t''.''weight'' + 0.5</font></code> | |||
t.weight := t.weight + 0.5 | |||
</syntaxhighlight> | |||
The tuple tags are optional, so that it is also possible to write a tuple type as <code> |
The tuple tags are optional, so that it is also possible to write a tuple type as <code>TUPLE </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> |
The precise specification of e.g. <code>TUPLE </code> is that it describes sequences of ''at least'' three elements, the first three being of types <code>A</code>, <code>B</code>, <code>C</code> respectively. As a result, <code>TUPLE </code> conforms to (may be assigned to) <code>TUPLE </code>, to <code>TUPLE </code> and to <code>TUPLE</code> (without parameters), the topmost tuple type to which all tuple types conform. | ||
===Agents=== | ===Agents=== | ||
Eiffel |
Eiffel's "agent" mechanism wraps operations into objects. This mechanism can be used for iteration, ], and other contexts in which it is useful to pass operations around the program structure. Other programming languages, especially ones that emphasize ], allow a similar pattern using ], ], or ]; Eiffel's agents emphasize the language's object-oriented paradigm, and use a syntax and semantics similar to code blocks in ] and ]. | ||
For example, to |
For example, to execute the <code>my_action</code> block for each element of <code>my_list</code>, one would write: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''my_action'')</font></code> | |||
my_list.do_all (agent my_action) | |||
</syntaxhighlight> | |||
To execute <code>my_action</code> only on elements satisfying <code>my_condition</code>, a limitation/filter can be added: | |||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''my_action'', '''agent''' ''my_condition'')</font></code> | |||
my_list.do_if (agent my_action, agent my_condition) | |||
</syntaxhighlight> | |||
In these examples, <code> |
In these examples, <code>my_action</code> and <code>my_condition</code> are routines. Prefixing them with <code>agent</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>a</code> represents that object (for example because <code>a</code> is the argument to <code>do_all</code>), the instruction | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''a''.''call'' ()</font></code> | |||
a.call () | |||
</syntaxhighlight> | |||
will call the original routine with the argument <code> |
will call the original routine with the argument <code>x</code>, as if we had directly called the original routine: <code>my_action (x)</code>. Arguments to <code>call</code> are passed as a tuple, here <code></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> |
It is possible to keep some arguments to an agent '''open''' and make others '''closed'''. The open arguments are passed as arguments to <code>call</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>action2</code> has two arguments, the iteration | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_list''.''do_all'' ('''agent''' ''action2'' ('''?''', ''y'')</font></code> | |||
my_list.do_all (agent action2 (?, y)) | |||
</syntaxhighlight> | |||
iterates <code> |
iterates <code>action2 (x, y)</code> for successive values of <code>x</code>, where the second argument remains set to <code>y</code>. The question mark <code>?</code> indicates an open argument; <code>y</code> is a closed argument of the agent. Note that the basic syntax <code>agent f</code> is a shorthand for <code>agent f (?, ?, ...)</code> with all arguments open. It is also possible to make the ''target'' of an agent open through the notation <code>{T}?</code> where <code>T</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> |
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>action2 (?, y)</code> with some operands closed and some open corresponds to a version of the original operation '']'' on the closed operands. | ||
The agent mechanism |
The agent mechanism also allows defining an agent without reference to an existing routine (such as <code>my_action</code>, <code>my_condition</code>, <code>action2</code>), through inline agents as in | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_list''.''do_all'' | |||
my_list.do_all (agent (s: STRING) | |||
|
require | ||
|
not_void: s /= Void | ||
|
do | ||
|
s.append_character (',') | ||
|
ensure | ||
|
appended: s.count = old s.count + 1 | ||
|
end) | ||
</syntaxhighlight> | |||
)</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: | 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: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_list''.''for_all'' ('''agent''' (''x'': ''INTEGER''): ''BOOLEAN'' '''do''' ''Result'' := (''x'' > 0) '''end''')</font></code> | |||
my_list.for_all (agent (x: INTEGER): BOOLEAN do Result := (x > 0) end) | |||
</syntaxhighlight> | |||
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> |
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>valid_arguments</code> of <code>call</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=== | ===Once routines=== | ||
A routine can be |
A routine's result can be cached using the <code>once</code> keyword in place of <code>do</code>. Non-first calls to a routine require no additional computation or resource allocation, but simply return a previously computed result. A common pattern for "once functions" is to provide shared objects; the first call will create the object, subsequent ones will return the reference to that object. The typical scheme is: | ||
<syntaxhighlight lang="eiffel"> | |||
"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 | |||
once | |||
create Result.make (args) | |||
-- This creates the object and returns a reference to it through `Result'. | |||
end | |||
</syntaxhighlight> | |||
The returned object—<code>Result</code> in the example—can itself be mutable, but its reference remains the same. | |||
<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> | |||
Often "once routines" perform a required initialization: multiple calls to a library can include a call to the initialization procedure, but only the first such call will perform the required actions. Using this pattern initialization can be decentralized, avoiding the need for a special initialization module. "Once routines" are similar in purpose and effect to the ] in many programming languages, and to the ] used in Python. | |||
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. | |||
By default, a "once routine" is called ''once per thread''. The semantics can be adjusted to ''once per process'' or ''once per object'' by qualifying it with a "once key", e.g. <code>once ("PROCESS")</code>. | |||
"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=== | ===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: | 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> |
For example, <code>NEWSPAPER</code> may conform to <code>PUBLICATION</code>, but <code>INTEGER</code> converts to <code>REAL</code> (and does not inherit from it). | ||
The conversion mechanism simply generalizes the ad hoc conversion rules (such as indeed between <code> |
The conversion mechanism simply generalizes the ad hoc conversion rules (such as indeed between <code>INTEGER</code> and <code>REAL</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>DATE</code> class may be declared to convert to <code>STRING</code>; this makes it possible to create a string from a date simply through | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''my_string'' := ''my_date''</font></code> | |||
my_string := my_date | |||
</syntaxhighlight> | |||
as a shortcut for using an explicit object creation with a conversion procedure: | as a shortcut for using an explicit object creation with a conversion procedure: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>'''create''' ''my_string''.make_from_date (''my_date'')</font></code> | |||
create my_string.make_from_date (my_date) | |||
</syntaxhighlight> | |||
To make the first form possible as a synonym for the |
To make the first form possible as a synonym for the second, it suffices to list the creation procedure (constructor) <code>make_from_date</code> in a <code>convert</code> clause at the beginning of the class. | ||
As another example, if there is such a conversion procedure listed from <code> |
As another example, if there is such a conversion procedure listed from <code>TUPLE </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> | |||
<syntaxhighlight lang="eiffel"> | |||
Bastille_day := | |||
</syntaxhighlight> | |||
===Exception handling=== | ===Exception handling=== | ||
] in Eiffel is based on the principles of design by contract. For example, an exception occurs when a routine's caller fails to satisfy a precondition, or when a routine cannot ensure a promised postcondition. In Eiffel, exception handling is not used for ] or to correct data-input mistakes. | |||
{{ Underconstruction }} | |||
An Eiffel exception handler is defined using the {{mono|rescue}} keyword. Within the {{mono|rescue}} section, the {{mono|retry}} keyword executes the routine again. For example, the following routine tracks the number of attempts at executing the routine, and only retries a certain number of times: | |||
<syntaxhighlight lang="eiffel"> | |||
connect_to_server (server: SOCKET) | |||
-- Connect to a server or give up after 10 attempts. | |||
require | |||
server /= Void and then server.address /= Void | |||
local | |||
attempts: INTEGER | |||
do | |||
server.connect | |||
ensure | |||
connected: server.is_connected | |||
rescue | |||
if attempts < 10 then | |||
attempts := attempts + 1 | |||
retry | |||
end | |||
end | |||
</syntaxhighlight> | |||
This example is arguably flawed for anything but the simplest programs, however, because connection failure is to be expected. For most programs a routine name like {{mono|attempt_connecting_to_server}} would be better, and the postcondition would not promise a connection, leaving it up to the caller to take appropriate steps if the connection was not opened. | |||
===Concurrency=== | |||
A number of networking and threading libraries are available, such as EiffelNet and EiffelThreads. A concurrency model for Eiffel, based on the concepts of design by contract, is ], or ''Simple Concurrent Object-Oriented Programming'', not yet part of the official language definition but available in ]. CAMEO<ref>{{cite journal|last=Brooke|first=Phillip|author2=Richard Paige|title=Cameo: An Alternative Model of Concurrency for Eiffel|journal=Formal Aspects of Computing|publisher=Springer|year=2008|doi=10.1007/s00165-008-0096-1|volume=21|issue=4|pages=363–391|s2cid=18336088|url=https://hal.archives-ouvertes.fr/hal-00534917/file/PEER_stage2_10.1007%252Fs00165-008-0096-1.pdf}}</ref> is an (unimplemented) variation of SCOOP for Eiffel. Concurrency also interacts with exceptions. Asynchronous exceptions can be troublesome (where a routine raises an exception after its caller has itself finished).<ref>{{cite journal|last=Brooke|first=Phillip|author2=Richard Paige|title=Exceptions in Concurrent Eiffel|journal=Journal of Object Technology|volume=6|issue=10|year=2007|url=http://www.jot.fm/issues/issue_2007_11/article4/|pages=111–126|doi=10.5381/jot.2007.6.10.a4|doi-access=free}}</ref> | |||
===Operator and bracket syntax, assigner commands=== | ===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 such as | |||
<syntaxhighlight lang="eiffel"> | |||
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 | |||
</syntaxhighlight> | |||
is conceptually understood as if it were the method call | |||
<code><font color=blue>''a'' + ''b''</font></code> | |||
<syntaxhighlight lang="eiffel"> | |||
is conceptually understood as if it were a function call | |||
a.plus (b) | |||
</syntaxhighlight> | |||
|
with target <code>a</code>, feature <code>plus</code> and argument <code>b</code>. | ||
Of course, the former is the conventional syntax and usually preferred. Operator syntax makes it possible to use either form by declaring the feature (for example in <code>INTEGER</code>, but this applies to other basic classes and can be used in any other for which such an operator is appropriate): | |||
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>. | |||
<syntaxhighlight lang="eiffel"> | |||
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): | |||
plus alias "+" (other: INTEGER): INTEGER | |||
-- ... Normal function declaration... | |||
end | |||
</syntaxhighlight> | |||
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. | |||
<code><font color=blue>''plus'' '''alias''' "+" (''other'': ''INTEGER''): ''INTEGER'' | |||
... Normal function declaration... | |||
'''end'''</font></code> | |||
Every class may in addition have ''one'' function aliased to "", the "bracket" operator, allowing the notation <code>a </code> as a synonym for <code>a.f (i, ...)</code> where <code>f</code> is the chosen function. This is particularly useful for container structures such as arrays, ]s, lists etc. For example, access to an element of a hash table with string keys can be written | |||
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. | |||
<syntaxhighlight lang="eiffel"> | |||
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 | |||
number := phone_book | |||
</syntaxhighlight> | |||
"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>a.x := v</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>''number'' := ''phone_book'' </font></code> | |||
<syntaxhighlight lang="eiffel"> | |||
"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 | |||
item alias "" (key: STRING): ELEMENT | |||
-- The element of key `key'. | |||
-- ("Getter" query) | |||
do | |||
... | |||
end | |||
put (e: ELEMENT; key: STRING) | |||
<code><font color=blue>''item'' '''alias''' "" (''key'': ''STRING''): ''ELEMENT''</font></code> <code><font color=blue> | |||
-- Insert the element `e', associating it with the key `key'. | |||
-- ("Setter" command) | |||
|
do | ||
... | |||
|
end | ||
</syntaxhighlight> | |||
<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: | Then to insert an element you have to use an explicit call to the setter command: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''phone_book''.''put'' (''New_person'', "JILL SMITH")</font></code> | |||
phone_book.put (New_person, "JILL SMITH") | |||
</syntaxhighlight> | |||
It is possible to write this equivalently as | It is possible to write this equivalently as | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''phone_book'' := ''New_person''</font></code> | |||
phone_book := New_person | |||
</syntaxhighlight> | |||
(in the same way that <code> |
(in the same way that <code>phone_book </code> is a synonym for <code>number := phone_book.item ("JILL SMITH")</code>), provided the declaration of <code>item</code> now starts (replacement for ) with | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color=blue>''item'' '''alias''' "" (''key'': ''STRING''): ''ELEMENT'' '''assign''' ''put''</font></code> | |||
item alias "" (key: STRING): ELEMENT assign put | |||
</syntaxhighlight> | |||
This declares <code> |
This declares <code>put</code> as the assigner command associated with <code>item</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>phone_book.item ("JILL SMITH") := New_person</code>. | ||
Note: The argument list of a's assigner is constrained to be: (a's return type;all of a's argument list...) | |||
===Lexical and syntax properties=== | ===Lexical and syntax properties=== | ||
Eiffel is not case-sensitive. The tokens <code> |
Eiffel is not case-sensitive. The tokens <code>make</code>, <code>maKe</code> and <code>MAKE</code> all denote the same identifier. See, however, the "style rules" below. | ||
Comments are introduced by <code |
Comments are introduced by <code>--</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. | 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. | 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: | 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: | ||
<syntaxhighlight lang="eiffel"> | |||
<code><font color="blue">'''class''' ''HASH_TABLE'' '''inherit''' | |||
|
class HASH_TABLE inherit TABLE | ||
'''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. | |||
feature -- Initialization | |||
===Style rules=== | |||
-- ... Declarations of initialization commands (creation procedures/constructors) ... | |||
feature -- Access | |||
Eiffel is distinguished by strong style rules, designed to enforce a consistent look-and-feel. | |||
-- ... Declarations of non-Boolean queries on the object state, e.g. item ... | |||
feature -- Status report | |||
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>). | |||
-- ... Declarations of Boolean queries on the object state, e.g. is_empty ... | |||
feature -- Element change | |||
The recommended style also suggests underscore to separate components of a multi-word identifier, as in <code><font color=blue>''average_temperature''</font></code>. | |||
-- ... Declarations of commands that change the structure, e.g. put ... | |||
-- etc. | |||
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. | |||
end | |||
</syntaxhighlight> | |||
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. | |||
===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 ], 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 ] 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: | |||
<code><font color=blue> | |||
'''from''' ''i'' := 0 '''until''' ''i'' >= 10 '''loop''' | |||
''my_array''.''put'' (0, ''i'') | |||
''i'' := ''i'' + ''1'' | |||
'''end''' | |||
</font></code> | |||
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 ]. 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 ]s except one (]) output C ] as an ], to submit to a C compiler, for ] and ]. On .NET, the ] compiler directly generates CIL (Common Intermediate Language) code for the .NET virtual machine. The ] compiler can also output Java bytecode. | |||
== Background == | |||
Eiffel was originally developed by ], a company founded by ] (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 ], ], ], ], type-safe conversions, and ]. Its most important contribution to ] is ] (DbC), in which ], ]s, ]s, and ]s are used to assist in assuring program correctness without sacrificing efficiency. | |||
Eiffel also offers multiple class inheritance. Many people (such as the designers of ]) 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 ]s. 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. | |||
], an ] for Eiffel available under both an ] and a commercial licenses, offers an object-oriented environment for ], using some innovative user-interface techniques such as Pick-And-Drop. There are two alternative, also ] implementations, ] - the GNU implementation, based on an older version of the language, and , which provides a more "traditional" interface. So does ], a plugin for ] 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 ] was based on Eiffel, but it has diverged, and now includes several ] features. | |||
== Specifications and standards== | |||
The Eiffel language definition is an international standard of ISO, the ]. The standard was developed by ] and its first version approved by ECMA on ] ] as ECMA standard 367, <cite>Eiffel: Analysis, Design and Implementation Language</cite>. The second edition was adopted by ECMA in ] ] and in the same month by ISO. Its text can be found, and used free of charge, on the ECMA site<ref>ECMA International: <cite>Standard ECMA-367 —Eiffel: Analysis, Design and Programming Language 2nd edition (June 2006)</cite>; available online at </ref>. 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 ] 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. | |||
===Style conventions=== | |||
The standard cites the following as earlier Eiffel Language specifications: | |||
Much of the documentation of Eiffel uses distinctive style conventions, designed to enforce a consistent look-and-feel. Some of these conventions apply to the code format itself, and others to the standard typographic rendering of Eiffel code in formats and publications where these conventions are possible. | |||
* Bertrand Meyer: <cite>Eiffel: The Language</cite>, Prentice Hall, second printing, 1992 (first printing: 1991) | |||
* Bertrand Meyer: <cite>Standard Eiffel</cite> (revision of preceding entry), ongoing, 1997-present, at , and | |||
*Bertrand Meyer: <cite>Object-Oriented Software Construction</cite>, Prentice Hall: first edition, 1988; second edition, 1997. | |||
While the language is case-insensitive, the style standards prescribe the use of all-capitals for class names (<code>LIST</code>), all-lower-case for feature names (<code>make</code>), and initial capitals for constants (<code>Avogadro</code>). The recommended style also suggests underscore to separate components of a multi-word identifier, as in <code>average_temperature</code>. | |||
The ETL3 page requires a password for access which can be found at under | |||
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>italics</code>'', comments, operators, and punctuation marks in <code>Roman</code>, with program text in <code>blue</code> as in the present article to distinguish it from explanatory text. For example, the "Hello, world!" program given above would be rendered as below in Eiffel documentation: | |||
== Differences between SmartEiffel and other implementations == | |||
* ] is currently unable to compile the open-source ] library from Eiffel Software. | |||
* SmartEiffel is case-sensitive. | |||
<syntaxhighlight lang="eiffel"> | |||
== A "Hello World" class == | |||
class | |||
<code><font color=blue>'''class''' | |||
|
HELLO_WORLD | ||
create | |||
|
make | ||
feature | |||
|
make | ||
|
do | ||
|
print ("Hello, world!") | ||
|
end | ||
end | |||
'''end''' | |||
</syntaxhighlight> | |||
'''end'''</font></code> | |||
===Interfaces to other tools and languages=== | |||
== References == | |||
Eiffel is a purely object-oriented language but provides an ] for interfacing with "external" software in any other programming language. | |||
<references/> | |||
*''Object-Oriented Software Construction'', Second Edition, by ], Prentice Hall, 1997, ISBN 0-13-629155-4 (see its ]); contains a detailed treatment of the concepts and theory of object technology, which led to the design of Eiffel. Available in several languages. | |||
It is possible for example to program machine- and operating-system level operations in ]. 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). | |||
== See also == | |||
* ] | |||
* ] | |||
* ] which includes the Eiffel-based Apple Media Language | |||
There is no direct connection between Eiffel and C. However, many Eiffel ]s (] is one exception) emit C ] as an ], to submit to a C compiler, for ] or ]. As such, they are examples of ]s. The Eiffel Compiler tecomp can execute Eiffel code directly (like an interpreter) without going via an intermediate C code or emit C code which will be passed to a C compiler to obtain optimized native code. On ], the ] compiler directly generates ] (CIL) code. The ] compiler can also emit ]. | |||
== External links == | |||
* | |||
* web site of the company that introduced Eiffel, was Interactive Software Engineering (ISE). | |||
* Eiffel tutorial (100 pages) by ] (, ) | |||
* , revision 2 (2006); this is the ECMA standard, with free access, its text identical to that of the ISO standard. | |||
* fairly complete Eiffel compiler, released under GNU GPL license, was SmallEiffel, not ECMA standard compliant. | |||
* an ] implementation of Eiffel creating ] for X86 systems (Windows, Linux) | |||
* Nonprofit International Consortium for Eiffel. | |||
* Includes a comprehensive Eiffel Software Directory | |||
* | |||
* | |||
==References== | |||
{{Reflist}} | |||
==External links== | |||
* subset | |||
* web site of the company that introduced Eiffel, was Interactive Software Engineering (ISE). | |||
* web site of the free GNU Eiffel development system. | |||
{{Ecma International Standards}} | |||
] | |||
{{Authority control}} | |||
] | |||
] | |||
{{DEFAULTSORT:Eiffel (Programming Language)}} | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] | |||
] |
Latest revision as of 06:47, 29 November 2024
Object-oriented programming languageEiffel logo | |
Paradigm | Multi-paradigm: object-oriented, class-based, generic, concurrent |
---|---|
Designed by | Bertrand Meyer |
Developer | Eiffel Software |
First appeared | 1986; 38 years ago (1986) |
Stable release | EiffelStudio 24.05 / 14 June 2024; 6 months ago (2024-06-14) |
Typing discipline | static |
Implementation language | Eiffel |
Platform | Cross-platform |
OS | FreeBSD, Linux, macOS, OpenBSD, Solaris, Windows |
License | dual and enterprise |
Filename extensions | .e |
Website | eiffel |
Major implementations | |
EiffelStudio, LibertyEiffel, SmartEiffel, Visual Eiffel, Gobo Eiffel, "The Eiffel Compiler" tecomp | |
Influenced by | |
Ada, Simula, Z | |
Influenced | |
Ada 2012, Albatross, C#, D, Java, Racket, Ruby, Sather, Scala |
Eiffel is an object-oriented programming language designed by Bertrand Meyer (an object-orientation proponent and author of Object-Oriented Software Construction) and Eiffel Software. Meyer conceived the language in 1985 with the goal of increasing the reliability of commercial software development. The first version was released in 1986. In 2005, the International Organization for Standardization (ISO) released a technical standard for Eiffel.
The design of the language is closely connected with the Eiffel programming method. Both are based on a set of principles, including design by contract, command–query separation, the uniform-access principle, the single-choice principle, the open–closed principle, and option–operand separation.
Many concepts initially introduced by Eiffel were later added into Java, C#, and other languages. New language design ideas, particularly through the Ecma/ISO standardization process, continue to be incorporated into the Eiffel language.
Characteristics
The key characteristics of the Eiffel language include:
- An object-oriented program structure in which a class serves as the basic unit of decomposition.
- Design by contract tightly integrated with other language constructs.
- Automatic memory management, typically implemented by garbage collection.
- Inheritance, including multiple inheritance, renaming, redefinition, "select", non-conforming inheritance, and other mechanisms intended to make inheritance safe.
- Constrained and unconstrained generic programming
- A uniform type system handling both value and reference semantics in which all types, including basic types such as INTEGER, are class-based.
- Static typing
- Void safety, or static protection against calls on null references, through the attached-types mechanism.
- Agents, or objects that wrap computations, closely connected with closures and lambda calculus.
- Once routines, or routines evaluated only once, for object sharing and decentralized initialization.
- Keyword-based syntax in the ALGOL/Pascal tradition but separator-free, insofar as semicolons are optional, with operator syntax available for routines.
- Case insensitivity
- Simple Concurrent Object-Oriented Programming (SCOOP) facilitates creation of multiple, concurrently active execution vehicles at a level of abstraction above the specific details of these vehicles (e.g. multiple threads without specific mutex management).
Design goals
Eiffel emphasizes declarative statements over procedural code and attempts to eliminate 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, extensible, reusable, and reliable answers to computing problems. Compilers for computer programs written in Eiffel provide extensive optimization techniques, such as automatic in-lining, that relieve the programmer of part of the optimization burden.
Background
Eiffel was originally developed by Eiffel Software, a company founded by Bertrand Meyer. Object-Oriented Software Construction contains a detailed treatment of the concepts and theory of the object technology that led to Eiffel's design.
The design goal behind the Eiffel language, libraries, and programming methods is to enable programmers to create reliable, reusable software modules. Eiffel supports multiple inheritance, genericity, polymorphism, encapsulation, type-safe conversions, and parameter covariance. Eiffel's most important contribution to software engineering is design by contract (DbC), in which assertions, preconditions, postconditions, and class invariants are employed to help ensure program correctness without sacrificing efficiency.
Eiffel's design is based on object-oriented programming theory, with only minor influence of other paradigms or concern for support of legacy code. Eiffel formally supports abstract data types. Under Eiffel's design, a software text should be able to reproduce its design documentation from the text itself, using a formalized implementation of the "Abstract Data Type".
Implementations and environments
EiffelStudio is an integrated development environment available under either an open source or a commercial license. It offers an object-oriented environment for software engineering. EiffelEnvision is a plug-in for Microsoft Visual Studio that allows users to edit, compile, and debug Eiffel projects from within the Microsoft Visual Studio IDE. Five other open source implementations are available: "The Eiffel Compiler" tecomp; Gobo Eiffel; SmartEiffel, the GNU implementation, based on an older version of the language; LibertyEiffel, based on the SmartEiffel compiler; and Visual Eiffel.
Several other programming languages incorporate elements first introduced in Eiffel. Sather, for example, was originally based on Eiffel but has since diverged, and now includes several functional programming features. The interactive-teaching language Blue, forerunner of BlueJ, is also Eiffel-based. The Apple Media Tool includes an Eiffel-based Apple Media Language.
Specifications and standards
The Eiffel language definition is an international standard of the ISO. The standard was developed by ECMA International, which first approved the standard on 21 June 2005 as Standard ECMA-367, Eiffel: Analysis, Design and Programming Language. In June 2006, ECMA and ISO adopted the second version. In November 2006, ISO first published that version. The standard can be found and used free of charge on the ECMA site. The ISO version is identical in all respects except formatting.
Eiffel Software, "The Eiffel Compiler" tecomp and Eiffel-library-developer Gobo have committed to implementing the standard; Eiffel Software's EiffelStudio 6.1 and "The Eiffel Compiler" tecomp implement some of the major new mechanisms—in particular, inline agents, assigner commands, bracket notation, non-conforming inheritance, and attached types. 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 disclosed whether future versions of its Eiffel compiler will comply with the standard. LibertyEiffel implements a dialect somewhere in between the SmartEiffel language and the standard.
The standard cites the following, predecessor 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.
- Bertrand Meyer: Touch of Class: Learning to Program Well with Objects and Contracts, Springer-Verlag, 2009 ISBN 978-3-540-92144-8 lxiv + 876 pages Full-color printing, numerous color photographs
The current version of the standard from June 2006 contains some inconsistencies (e.g. covariant redefinitions). The ECMA committee has not yet announced any timeline and direction on how to resolve the inconsistencies.
Syntax and semantics
Overall structure
An Eiffel "system" or "program" is a collection of classes. Above the level of classes, Eiffel defines cluster, which is essentially a group of classes, and possibly of subclusters (nested clusters). Clusters are not a syntactic language construct, but rather a standard organizational convention. Typically an Eiffel program will be organized with each class in a separate file, and each cluster in a directory containing class files. In this organization, subclusters are subdirectories. For example, under standard organizational and casing conventions, x.e
might be the name of a file that defines a class called X.
A class contains features, which are similar to "routines", "members", "attributes" or "methods" in other object-oriented programming languages. A class also defines its invariants, and contains other properties, such as a "notes" section for documentation and metadata. Eiffel's standard data types, such as INTEGER
, STRING
and ARRAY
, are all themselves classes.
Every system must have a class designated as "root", with one of its creation procedures designated as "root procedure". Executing a system consists of creating an instance of the root class and executing its root procedure. Generally, doing so creates new objects, calls new features, and so on.
Eiffel has five basic executable instructions: assignment, object creation, routine call, condition, and iteration. Eiffel's control structures are strict in enforcing structured programming: every block has exactly one entry and exactly one exit.
Scoping
Unlike many object-oriented languages, but like Smalltalk, Eiffel does not permit any assignment into attributes of objects, except within the features of an object, which is the practical application of the principle of information hiding or data abstraction, requiring formal interfaces for data mutation. To put it in the language of other object-oriented programming languages, all Eiffel attributes are "protected", and "setters" are needed for client objects to modify values. An upshot of this is that "setters" can and normally do, implement the invariants for which Eiffel provides syntax.
While Eiffel does not allow direct access to the features of a class by a client of the class, it does allow for the definition of an "assigner command", such as:
some_attribute: SOME_TYPE assign set_some_attribute set_some_attribute (v: VALUE_TYPE) -- Set value of some_attribute to `v'. do some_attribute := v end
While a slight bow to the overall developer community to allow something looking like direct access (e.g. thereby breaking the Information Hiding Principle), the practice is dangerous as it hides or obfuscates the reality of a "setter" being used. In practice, it is better to redirect the call to a setter rather than implying a direct access to a feature like some_attribute
as in the example code above.
Unlike other languages, having notions of "public", "protected", "private" and so on, Eiffel uses an exporting technology to more precisely control the scoping between client and supplier classes. Feature visibility is checked statically at compile-time. For example, (below), the "{NONE}" is similar to "protected" in other languages. Scope applied this way to a "feature set" (e.g. everything below the 'feature' keyword to either the next feature set keyword or the end of the class) can be changed in descendant classes using the "export" keyword.
feature {NONE} -- Initialization default_create -- Initialize a new `zero' decimal instance. do make_zero end
Alternatively, the lack of a {x} export declaration implies {ANY} and is similar to the "public" scoping of other languages.
feature -- Constants
Finally, scoping can be selectively and precisely controlled to any class in the Eiffel project universe, such as:
feature {DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER} -- Access
Here, the compiler will allow only the classes listed between the curly braces to access the features within the feature group (e.g. DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER).
"Hello, world!"
A programming language's look and feel is often conveyed using a "Hello, world!" program. Such a program written in Eiffel might be:
class HELLO_WORLD create make feature make do print ("Hello, world!%N") end end
This program contains the class HELLO_WORLD
. The constructor (create routine) for the class, named make
, invokes the print
system library routine to write a "Hello,
world!"
message to the output.
Design by contract
Further information: Design by contractThe concept of Design by Contract is central to Eiffel. The contracts assert what must be true before a routine is executed (precondition) and what must hold to be true after the routine finishes (post-condition). Class Invariant contracts define what assertions must hold true both before and after any feature of a class is accessed (both routines and attributes). Moreover, contracts codify into executable code developer and designers assumptions about the operating environment of the features of a class or the class as a whole by means of the invariant.
The Eiffel compiler is designed to include the feature and class contracts in various levels. EiffelStudio, for example, executes all feature and class contracts during execution in the "Workbench mode." When an executable is created, the compiler is instructed by way of the project settings file (e.g. ECF file) to either include or exclude any set of contracts. Thus, an executable file can be compiled to either include or exclude any level of contract, thereby bringing along continuous levels of unit and integration testing. Moreover, contracts can be continually and methodically exercised by way of the Auto-Test feature found in EiffelStudio.
The Design by Contract mechanisms are tightly integrated with the language and guide redefinition of features in inheritance:
- Routine precondition: The precondition may only be weakened by inheritance; any call that meets the requirements of the ancestor meets those of the descendant.
- Routine postcondition: The postcondition can only be strengthened by inheritance; any result guaranteed by the ancestor is still provided by the descendant.
- Class invariant: Conditions that must hold true after the object's creation and after any call to an exported class routine. Because the invariant is checked so often, it makes it simultaneously the most expensive and most powerful form of condition or contract.
In addition, the language supports a "check instruction" (a kind of "assert"), loop invariants, and loop variants (which guarantee loop termination).
Void-safe capability
Further information: Void safetyVoid-safe ability, like static typing, is another facility for improving software quality. Void-safe software is protected from runtime errors caused by calls to void references, and therefore will be more reliable than software in which calls to void targets can occur. The analogy to static typing is a useful one. Void-safe ability can be seen as an extension to the type system, or a step beyond static typing, because the mechanism for ensuring void safety is integrated into the type system.
The guard against void target calls can be seen by way of the notion of attachment and (by extension) detachment (e.g. detachable keyword). The void-safe facility can be seen in a short re-work of the example code used above:
some_attribute: detachable SOME_TYPE use_some_attribute -- Set value of some_attribute to `v'. do if attached some_attribute as l_attribute then do_something (l_attribute) end end do_something (a_value: SOME_TYPE) -- Do something with `a_value'. do ... doing something with `a_value' ... end
The code example above shows how the compiler can statically address the reliability of whether some_attribute
will be attached or detached at the point it is used. Notably, the attached
keyword allows for an "attachment local" (e.g. l_attribute
), which is scoped to only the block of code enclosed by the if-statement construct. Thus, within this small block of code, the local variable (e.g. l_attribute
) can be statically guaranteed to be non-void (i.e. void safe).
Features: commands and queries
The primary characteristic of a class is that it defines a set of features: as a class represents a set of run-time objects, or "instances", a feature is an operation on these objects. There are two kinds of features: queries and commands. A query provides information about an instance. A command modifies an instance.
The command-query distinction is important to the Eiffel method. In particular:
- Uniform-Access Principle: from the point of view of a software client making a call to a class feature, whether a query is an attribute (field value) or a function (computed value) should not make any difference. For example,
a_vehicle.speed
could be an attribute accessed on the objecta_vehicle
, or it could be computed by a function that divides distance by time. The notation is the same in both cases, so that it is easy to change the class's implementation without affecting client 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" functions 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.
Overloading
Eiffel does not allow argument overloading. Each feature name within a class always maps to a specific feature within the class. One name, within one class, means one thing. This design choice helps the readability of classes, by avoiding a cause of ambiguity about which routine will be invoked by a call. It also simplifies the language mechanism; in particular, this is what makes Eiffel's multiple inheritance mechanism possible.
Names can, of course, be reused in different classes. For example, the feature plus (along with its infix alias "+") is defined in several classes: INTEGER, REAL, STRING, etc.
Genericity
See also: Generic programming § Genericity in EiffelA generic class is a class that varies by type (e.g. LIST , a list of phone numbers; ACCOUNT , allowing for ACCOUNT and ACCOUNT , etc.). 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
and 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 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 an 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
See for a complete discussion of Eiffel inheritance.
Deferred classes and features
Classes may be defined with deferred class
rather than with class
to indicate that the class may not be directly instantiated. Non-instantiatable classes are called abstract classes in some other object-oriented programming languages. In Eiffel parlance, only an "effective" class can be instantiated (it may be a descendant of a deferred class). A feature can also be deferred by using the deferred
keyword in place of a do
clause. If a class has any deferred features it must be declared as deferred; however, a class with no deferred features may nonetheless itself be deferred.
Deferred classes play some of the same role as interfaces in languages such as Java, though many object-oriented programming theorists believe interfaces are themselves largely an answer to Java's lack of multiple inheritance (which Eiffel has).
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 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 used 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's "agent" mechanism wraps operations into objects. This mechanism can be used for iteration, event-driven programming, and other contexts in which it is useful to pass operations around the program structure. Other programming languages, especially ones that emphasize functional programming, allow a similar pattern using continuations, closures, or generators; Eiffel's agents emphasize the language's object-oriented paradigm, and use a syntax and semantics similar to code blocks in Smalltalk and Ruby.
For example, to execute the my_action
block for each element of my_list
, one would write:
my_list.do_all (agent my_action)
To execute my_action
only on elements satisfying my_condition
, a limitation/filter can be added:
my_list.do_if (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 argument remains 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 shorthand 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 also allows 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 (s: STRING) require not_void: s /= Void do s.append_character (',') ensure appended: s.count = old s.count + 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's result can be cached using the once
keyword in place of do
. Non-first calls to a routine require no additional computation or resource allocation, but simply return a previously computed result. A common pattern for "once functions" is 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 once create Result.make (args) -- This creates the object and returns a reference to it through `Result'. end
The returned object—Result
in the example—can itself be mutable, but its reference remains the same.
Often "once routines" perform a required initialization: multiple calls to a library can include a call to the initialization procedure, but only the first such call will perform the required actions. Using this pattern initialization can be decentralized, avoiding the need for a special initialization module. "Once routines" are similar in purpose and effect to the singleton pattern in many programming languages, and to the Borg pattern used in Python.
By default, a "once routine" is called once per thread. The semantics can be adjusted to once per process or once per object by qualifying it with a "once key", e.g. once ("PROCESS")
.
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 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 DATE
class may be declared to convert to STRING
; 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 second, 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
Exception handling in Eiffel is based on the principles of design by contract. For example, an exception occurs when a routine's caller fails to satisfy a precondition, or when a routine cannot ensure a promised postcondition. In Eiffel, exception handling is not used for control flow or to correct data-input mistakes.
An Eiffel exception handler is defined using the rescue keyword. Within the rescue section, the retry keyword executes the routine again. For example, the following routine tracks the number of attempts at executing the routine, and only retries a certain number of times:
connect_to_server (server: SOCKET) -- Connect to a server or give up after 10 attempts. require server /= Void and then server.address /= Void local attempts: INTEGER do server.connect ensure connected: server.is_connected rescue if attempts < 10 then attempts := attempts + 1 retry end end
This example is arguably flawed for anything but the simplest programs, however, because connection failure is to be expected. For most programs a routine name like attempt_connecting_to_server would be better, and the postcondition would not promise a connection, leaving it up to the caller to take appropriate steps if the connection was not opened.
Concurrency
A number of networking and threading libraries are available, such as EiffelNet and EiffelThreads. A concurrency model for Eiffel, based on the concepts of design by contract, is SCOOP, or Simple Concurrent Object-Oriented Programming, not yet part of the official language definition but available in EiffelStudio. CAMEO is an (unimplemented) variation of SCOOP for Eiffel. Concurrency also interacts with exceptions. Asynchronous exceptions can be troublesome (where a routine raises an exception after its caller has itself finished).
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 such as
a + b
is conceptually understood as if it were the method call
a.plus (b)
with target a
, feature plus
and argument b
.
Of course, the former 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 is 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) -- 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
.
Note: The argument list of a's assigner is constrained to be: (a's return type;all of a's argument list...)
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 conventions
Much of the documentation of Eiffel uses distinctive style conventions, designed to enforce a consistent look-and-feel. Some of these conventions apply to the code format itself, and others to the standard typographic rendering of Eiffel code in formats and publications where these conventions are possible.
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. For example, the "Hello, world!" program given above would be rendered as below in Eiffel documentation:
class HELLO_WORLD create make feature make do print ("Hello, world!") end end
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).
There is no direct connection between Eiffel and C. However, many Eiffel compilers (Visual Eiffel is one exception) emit C source code as an intermediate language, to submit to a C compiler, for optimizing or porting. As such, they are examples of transcompilers. The Eiffel Compiler tecomp can execute Eiffel code directly (like an interpreter) without going via an intermediate C code or emit C code which will be passed to a C compiler to obtain optimized native code. On .NET, the EiffelStudio compiler directly generates Common Intermediate Language (CIL) code. The SmartEiffel compiler can also emit Java bytecode.
References
- "Eiffel in a Nutshell". Eiffel Software. 1985–2012. Retrieved 29 November 2024.
- "EiffelStudio 24.05 is available!". Eiffel.org. 14 June 2024. Retrieved 29 November 2024.
- Cooper, Peter (2009). Beginning Ruby: From Novice to Professional. Beginning from Novice to Professional (2nd ed.). Berkeley: APress. p. 101. ISBN 978-1-4302-2363-4.
To a lesser extent, Python, LISP, Eiffel, Ada, and C++ have also influenced Ruby.
- "Eiffel – the Language". berenddeboer.net. Retrieved 6 July 2016.
- Meyer, Bertrand (2009-08-28). Touch of Class: Learning to Program Well with Objects and Contracts. Springer Science & Business Media. ISBN 978-3-540-92144-8.
- "Programming Languages - Eiffel" (PDF). Department of Computer Science, Virginia Tech. Retrieved 25 March 2023.
- Carl Friess. "Eiffel Syntax Guide". Eiffel Syntax Guide. Retrieved 25 March 2023.
- Claus Brabrand. "The E I F F E L Programming Language" (PDF). IT University of Copenhagen. Retrieved 25 March 2023.
- Object-Oriented Software Construction, Second Edition, by Bertrand Meyer, Prentice Hall, 1997, ISBN 0-13-629155-4
- ECMA International: Standard ECMA-367 – Eiffel: Analysis, Design and Programming Language 2nd edition (June 2006); available online at https://ecma-international.org/publications-and-standards/standards/ecma-367/
- International Organization for Standardization: Standard ISO/IEC DIS 25436, available online at
- Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October–November 2001, available online
- "9 INHERITANCE". Archive.eiffel.com. 1997-03-23. Retrieved 2013-07-08.
- "Multiple Inheritance and Interfaces". Artima.com. 2002-12-16. Retrieved 2013-07-08.
- "Multiple Inheritance Is Not Evil". C2.com. 2007-04-28. Retrieved 2013-07-08.
- 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
- Brooke, Phillip; Richard Paige (2008). "Cameo: An Alternative Model of Concurrency for Eiffel" (PDF). Formal Aspects of Computing. 21 (4). Springer: 363–391. doi:10.1007/s00165-008-0096-1. S2CID 18336088.
- Brooke, Phillip; Richard Paige (2007). "Exceptions in Concurrent Eiffel". Journal of Object Technology. 6 (10): 111–126. doi:10.5381/jot.2007.6.10.a4.
External links
- Eiffel Software web site of the company that introduced Eiffel, was Interactive Software Engineering (ISE).
- LibertyEiffel web site of the free GNU Eiffel development system.
Standards of Ecma International | ||
---|---|---|
Application interfaces | ||
File systems (tape) |
| |
File systems (disk) | ||
Graphics | ||
Programming languages | ||
Radio link interfaces | ||
Other | ||
List of Ecma standards (1961 – present) |