Author:admin

Date:2008-09-17T13:53:28.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@3 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
jfiat
2008-09-17 13:53:28 +00:00
parent 4fee9356ea
commit 2ee31ab9c7
763 changed files with 36576 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
[[Property:title|4 Classes]]
[[Property:link_title|I2E: Classes]]
[[Property:weight|-11]]
A class, it was said above, is an implementation of an abstract data type. This means that it describes a set of run-time objects, characterized by the ''' features''' (operations) applicable to them, and by the formal properties of these features.
Such objects are called the '''direct instances''' of the class. Classes and objects should not be confused: "class" is a compile-time notion, whereas objects only exist at run time. This is similar to the difference that exists in classical programming between a program and one execution of that program, or between a type and a run-time value of that type.
{{info|"Object-Oriented" is a misnomer; "Class-Oriented Analysis, Design and Programming" would be a more accurate description of the method. }}
To see what a class looks like, let us look at a simple example, <code> ACCOUNT </code>, which describes bank accounts. But before exploring the class itself it is useful to study how it maybe used by other classes, called it's '''clients'''.
A class <code> X </code> may become a client of <code> ACCOUNT </code> by declaring one or more '''entities''' of type <code> ACCOUNT </code>. Such a declaration is of the form:
<code>acc: ACCOUNT</code>
The term "entity" generalizes the more common notion of "variable". An entity declared of a reference type, such as <code>acc</code>, may at any time during execution become " '''attached to''' " an object; the type rules imply that this object must be a direct instance of <code> ACCOUNT </code> -- or, as seen below, of a "descendant" of that class.
[[Image:invitation-2]]
An entity is said to be void if it is not attached to any object. By default, entities are void at initialization. To obtain objects at run-time, a routine <code> r </code> appearing in the client class <code> X </code> may use a '''creation instruction''' of the form
<code>create acc</code>
which creates a new direct instance of <code> ACCOUNT </code>, attaches <code> acc </code> to that instance, and initializes all its fields to default values. A variant of this notation, studied below, makes it possible to override the default initializations.
Once the client has attached <code> acc </code> to an object, it may call on this object the features defined in class <code> ACCOUNT </code>. Here is an extract with some feature calls using <code> acc </code> as their target:
<code>acc.open ("Jill")
acc.deposit (5000)
if acc.may_withdraw (3000) then
acc.withdraw (3000)
print (acc.balance)
end</code>
These feature calls use dot notation, of the form <code> target </code> <span> <code> . </code> </span> <code> feature_name </code>, possibly followed by a list of arguments in parentheses. Features are of two kinds:
* '''Routines''', such as <code> open </code>, <code> deposit </code>, <code> may_withdraw </code>, <code> withdraw </code>, represent computations applicable to instances of the class.
* '''Attributes''' represent data items associated with these instances.
Routines are further divided into '''procedures''' (commands, which do not return a value) and '''functions''' (queries, returning a value). Here <code> may_withdraw </code> is a function returning a boolean; the other three-routines called are procedures.
{{info|A note on syntax: you may separate instructions by semicolons, and indeed you should when, as on the next-to-last line of the example, two or more instructions appear on a line. But the language's syntax has been designed so that the semicolon is almost always optional, regardless of the layout. Indeed the practice is to omit it between instructions or declarations on separate lines, as this results in lighter, clearer software texts. }}
In class <code> ACCOUNT </code>, is feature <code> balance </code> an attribute, or is it a function with no argument? The above extract of the client class <code> X </code> doesn't say, and this ambiguity is intentional. A client of <code> ACCOUNT </code> must not need to know how class <code> ACCOUNT </code> delivers an account's balance when requested: by looking up a field present in each account object, or by calling a function that computes the balance from other fields. Choosing between these techniques is the business of class <code> ACCOUNT </code>, not anybody else's. Because such implementation choices are often changed over the lifetime of a project, it is essential to protect clients against their effects. This is known as the '''Uniform Access Principle''', stating that the choice between representing a property through memory (an attribute) or through an algorithm (function) shall not affect how clients use it.
So much for how client classes will typically use <code> ACCOUNT. </code> Below is a first sketch of how class <code> ACCOUNT </code> itself might look. Line segments beginning with <code> -- </code> are comments. The class includes two <code> feature </code> clauses, introducing its features. The first begins with just the keyword <code> feature </code>, without further qualification; this means that the features declared in this clause are available (or "exported") to all clients of the class. The second clause is introduced by <code> feature </code> { <code> NONE </code>} to indicate that the feature that follows, called <code> add </code>, is available to no client. What appears between the braces is a list of client classes to which the corresponding features are available; <code> NONE </code> is a special class of the Kernel Library, which has no instances, so that <code> add </code> is in effect a secret feature, available only locally to the other routines of class <code> ACCOUNT </code>. So in a client class such as <code> X </code>, the call <code> acc </code> . <code> add </code> ( <code> -3000 </code>) would be invalid.
<code>class ACCOUNT
feature
balance: INTEGER
owner: PERSON
minimum_balance: INTEGER is 1000
open (who: PERSON) is
-- Assign the account to owner who.
do
owner := who
end
deposit (sum: INTEGER) is
-- Deposit sum into the account.
do
add (sum)
end
withdraw (sum: INTEGER) is
-- Withdraw sum from the account.
do
add (-sum)
end
may_withdraw (sum: INTEGER): BOOLEAN is
-- Is there enough money to withdraw sum?
do
Result := (balance >= sum + minimum_balance)
end
feature {NONE}
add (sum: INTEGER) is
-- Add sum to the balance
do
balance := balance + sum
end
end -- ACCOUNT
</code>
Let us examine the features in sequence. The <code> is </code> <code> ... </code> <code> do </code> <code> ... </code> <code> end </code> distinguishes routines from attributes. So here the class has implemented <code> balance </code> as an attribute, although, as noted, a function would also have been acceptable. Feature <code> owner </code> is also an attribute.
The language definition guarantees automatic initialization, so that the initial balance of an account object will be zero after a creation instruction. Each type has a default initial value: zero for <code> INTEGER </code> and <code> REAL </code>, false for <code> BOOLEAN </code>, null character for <code> CHARACTER </code>, and a void reference for reference types. The class designer may also provide clients with different initialization options, as will be seen below in a revised version of this example.
The other public features, <code> withdraw deposit, open, </code> and <code> may_withdraw </code> are straight-forward routines. The special entity <code> Result </code>, used in <code> may_withdraw </code>, denotes the function result; it is initialized on function entry to the default value of the function's result type. You may only use <code> Result </code> in functions.
The secret procedure <code> add </code> serves for the implementation of the public procedures <code> deposit </code> and <code> withdraw </code>; the designer of <code> ACCOUNT </code> judged it too general to be exported by itself. The clause <code> is </code> <code> 1000 </code> introduces <code> minimum_balance </code> as a constant attribute, which will not occupy any space in instances of the class; in contrast, every instance has a field for every non-constant attribute such as <code> balance </code>.
In Eiffel's object-oriented programming style any operation is relative to a certain object. A client invoking the operation specifies this object by writing the corresponding entity on the left of the dot, as <code> acc </code> in <code> acc </code>. <code> open </code> ( <code> "Jill" </code>). Within the class, however, the "current" instance to which operations apply usually remains implicit, so that unqualified feature names, such as <code> owner </code> in procedure <code> open </code> or <code> add </code> in <code> deposit </code>, mean "the <code> owner </code> attribute or <code> add </code> routine relative to the current instance".
If you need to denote the current object explicitly, you may use the special entity <code> Current </code>. For example the unqualified occurrences of <code> add </code> appearing in the class text above are equivalent to <code> Current </code>. <code> add </code>.
In some cases, infix or prefix notation will be more convenient than dot notation. For example, if a class <code> VECTOR </code> offers an addition routine, most people will feel more comfortable with calls of the form <code> v + w </code> than with the dot-notation call <code> v </code>. <code> plus </code> ( <code> w </code>). To make this possible it suffices to give the routine a name of the form <code> infix </code> "+" rather than <code> plus </code>; internally, however, the operation is still a normal routine call. Prefix operators are similarly available.
The above simple example has shown the basic structuring mechanism of the language: the class. A class describes objects accessible to clients through an official interface comprising some of the class features. Features are implemented as attributes or routines; the implementation of exported features may rely on other, secret ones.

View File

@@ -0,0 +1,30 @@
[[Property:title|12 Combining Genericity and Inheritance]]
[[Property:link_title|I2E: Combining Genericity and Inheritance]]
[[Property:weight|-3]]
Genericity and inheritance, the two fundamental mechanisms for generalizing classes, may be combined in two fruitful ways.
The first technique yields '''polymorphic data structures'''. Assume that in the generic class <code> LIST [ G ] </code> the insertion procedure <code> put </code> has a formal argument of type <code> G </code>, representing the element to be inserted. Then with a declaration such as
<code>pl: LIST [POLYGON]</code>
the type rules imply that in a call <code> pl </code>. <code> put </code> <code> ( "p" ) </code> the permitted types for the argument <code> p </code> include not just <code> POLYGON </code>, but also <code> RECTANGLE </code> (an heir of <code> POLYGON </code>) or any other type conforming to <code> POLYGON </code> through inheritance.
The basic conformance requirement used here is the inheritance-based type compatibility rule: <code> V </code> conforms to <code> T </code> if <code> V </code> is a descendant of <code> T </code>.
Structures such as <code> pl </code> may contain objects of different types, hence the name "polymorphic data structure". Such polymorphism is, again, made safe by the type rules: by choosing an actual generic parameter ( <code> POLYGON </code> in the example) based higher or lower in the inheritance graph, you extend or restrict the permissible types of objects in <code> pl </code>. A fully general list would be declared as
<code>LIST [ANY]</code>
where <code> ANY </code>, a Kernel Library class, is automatically an ancestor of any class that you may write.
The other mechanism for combining genericity and inheritance is '''constrained genericity'''. By indicating a class name after a formal generic parameter, as in
<code>VECTOR [T -> NUMERIC]</code>
you express that only descendants of that class (here <code> NUMERIC </code>) may be used as the corresponding actual generic parameters. This makes it possible to use the corresponding operations. Here, for example, class <code> VECTOR </code> may define a routine <code> infix </code> "+" for adding vectors, based on the corresponding routine from <code> NUMERIC </code> for adding vector elements. Then by making <code> VECTOR </code> itself inherit from <code> NUMERIC </code>, you ensure that it satisfies its own generic constraint and enable the definition of types such as <code> VECTOR </code> <code> [ </code> <code> VECTOR </code> <code> [ </code> <code> T </code> <code> ]] </code>.
As you have perhaps guessed, unconstrained genericity, as in <code> LIST </code> <code> [ G ] </code>, may be viewed as an abbreviation for genericity constrained by <code> ANY </code>, as in
<code>LIST [G -> ANY]</code>
Something else you may have guessed: if <code> ANY </code>, introduced in this session, is the top of the inheritance structure -- providing all classes with universal features such as <code> equal </code> to compare arbitrary objects and <code> clone </code> to duplicate objects -- then <code> NONE </code>, seen earlier in the notation <code> feature </code> <code> { </code> <code> NONE </code> <code> } </code>, is its bottom. <code> NONE </code> indeed conceptually inherits from all other classes. <code> NONE </code> is, among other things, the type of <code> ensure </code>, the void reference.

View File

@@ -0,0 +1,58 @@
[[Property:title|13 Deferred Classes and Seamless Development]]
[[Property:link_title|I2E: Deferred Classes and Seamless Development]]
[[Property:weight|-2]]
The inheritance mechanism includes one more major notion: deferred features and classes.
Declaring a feature <code> f </code> as deferred in a class <code> C </code> expresses that there is no default implementation of <code> f </code> in <code> C </code>; such implementations will appear in eventual descendants of <code> C </code>. A class that has one or more deferred routines is itself said to be deferred. A non-deferred routine or class -- like all those seen until now -- is said to be '''effective'''.
For example, a system used by a Department of Motor Vehicles to register vehicles might include a class of the form
<code>
deferred class
VEHICLE
feature
dues_paid (year: INTEGER): BOOLEAN is
do ... end
valid_plate (year: INTEGER): BOOLEAN is
do ... end
register (year: INTEGER) is
-- Register vehicle for year.
require
dues_paid (year)
deferred
ensure
valid_plate (year)
end
... Other features, deferred or effective ...
end -- VEHICLE
</code>
<code>This example assumes that no single registration algorithm applies to all kinds of vehicle; passenger cars, motorcycles, trucks etc. are all registered differently. But the same precondition and postcondition apply in all cases. The solution is to treat register as a deferred routine, making VEHICLE a deferred class. Descendants of class VEHICLE, such as CAR or TRUCK, effect this routine, that is to say, give effective versions. An effecting is similar to a redefinition; only here there is no effective definition in the original class, just a specification in the form of a deferred routine. The term '''redeclaration''' covers both redefinition and effecting.</code>
[[Image:invitation-5]]
<code> Whereas an effective class described an implementation of an abstract data types, a deferred class describes a set of possible implementations. You may not instantiate a deferred class: create v is invalid if v is declared of type VEHICLE. But you may assign to v a reference to an instance of an effective descendant of VEHICLE. For example, assuming CAR and TRUCK provide effective definitions for all deferred routines of VEHICLE, the following will be valid: </code>
<code>
v: VEHICLE; c: CAR; t: TRUCK
... create c; create t ...
if "Some test" then
v := c
else
v := t
end
v.register (2003)</code>
This example fully exploits polymorphism: depending on the outcome of "Some test", <code>v</code> will be treated as a car or a truck, and the appropriate registration algorithm will be applied. Also, "Some test" may depend on some event whose outcome is impossible to predict until run-time, for example the user clicking with the mouse to select one among several vehicle icons displayed on the screen.
Deferred classes are particularly useful at the design stage. The first version of a module may be a deferred class, which will later be refined into one or more effective classes. Eiffel's Design by Contract&#153; mechanisms are essential here: you may a precondition and a postcondition with a routine even though it is a deferred routine (as with register above), and an invariant with a class even though it is a deferred class. This enables you, as a designer, to attach precise semantics to a module at the design stage long before you will make any implementation choices.
Beyond design and implementation, these techniques extend to the earliest stage of development, analysis. Deferred classes written at that stage describe not software objects, but objects from the external world being modeled -- documents, airplanes, investments. Here again the presence of contracts to express constraints, and the language's other structuring facilities, provide an attractive combination.
Eiffel appears here in its full role of a lifecycle approach, covering areas traditionally considered separate: program implementation, the traditional province of development environments; system modeling and architecture, the traditional province of CASE tools based on UML or similar notations disconnected from the rest of the lifecycle. Eiffel instead emphasizes the fundamental unity of the software process and the usefulness of a single set of notations, concepts and tools applicable throughout. Such a seamless approach is indispensable to support the inevitable reversals that occur during the process of building software, such as detecting at implementation time a problem that leads to a change in the system's functionality, set at analysis time. The use of separate tools and notations, such as UML on one side and a programming language on the other, makes such round-trips difficult at best and often leads to monolithic, hard-to-change software. Eiffel lets you focus on the issues, without interposing artificial barriers between different software development activities. You'll use the fundamental problem-solving techniques -- data abstraction through classes, precise specification through contracts, modularity through information hiding, rational organization through inheritance, decentralized architecture through dynamic binding, parameterization of the solution through genericity, reusability through all these techniques -- all along; only the level of abstraction changes.

View File

@@ -0,0 +1,140 @@
[[Property:title|6 Design by Contract and Assertions]]
[[Property:link_title|I2E: Design by Contract and Assertions]]
[[Property:weight|-9]]
If classes are to deserve their definition as abstract data type implementations, they must be known not just by the available operations, but also by the formal properties of these operations, which did not yet appear in the preceding example.
==The role of assertions==
Eiffel encourages software developers to express formal properties of classes by writing '''assertions''', which may in particular appear in the following roles: <br/>
* Routine '''preconditions''' express the requirements that clients must satisfy whenever they call a routine. For example the designer of <code> ACCOUNT </code> may wish to permit a withdrawal operation only if it keeps the account's balance at or above the minimum. Preconditions are introduced by the keyword <code> require </code>.
* Routine '''postconditions''', introduced by the keyword <code> ensure </code>, express conditions that the routine (the supplier) guarantees on return, if the precondition was satisfied on entry.
* A class '''invariant''' must be satisfied by every instance of the class whenever the instance is externally accessible: after creation, and after any call to an exported routine of the class. The invariant appears in a clause introduced by the keyword <code> invariant </code>, and represents a general consistency constraint imposed on all routines of the class.
With appropriate assertions, the class <code> ACCOUNT </code> becomes:
<code>class ACCOUNT
create
make
feature
... Attributes as before:
balance , minimum_balance , owner , open ...
deposit (sum: INTEGER) is
-- Deposit sum into the account.
require
sum >= 0
do
add (sum)
ensure
balance = old balance + sum
end
withdraw (sum: INTEGER) is
-- Withdraw sum from the account.
require
sum >= 0
sum <= balance - minimum_balance
do
add (-sum)
ensure
balance = old balance - sum
end
may_withdraw ... -- As before
feature {NONE}
add ...
make (initial: INTEGER) is
-- Initialize account with balance initial.
require
initial >= minimum_balance
do
balance := initial
end
invariant
balance >= minimum_balance
end -- ACCOUNT
</code>
The notation <code> old </code> <code> expression </code> is only valid in a routine postcondition. It denotes the value the <code> expression </code> had on routine entry.
==Creation procedures==
In its last version above, the class now includes a creation procedure, <code> make </code>. With the first version, clients used creation instructions such as <code> create </code> <code> acc1 </code> to create accounts; but then the default initialization, setting balance to zero, violated the invariant. By having one or more creation procedures, listed in the <code> create </code> clause at the beginning of the class text, a class offers a way to override the default initializations. The effect of
<code>create acc1.make (5_500)</code>
is to allocate the object (as with the default creation) and to call procedure <code> make </code> on this object, with the argument given. This call is correct since it satisfies the precondition; it will ensure the invariant.
{{info|The underscore <code> _ </code> in the integer constant <code> 5_500 </code> has no semantic effect. The general rule is that you can group digits by sets of three from the right to improve the readability of integer constants. }}
Note that the same keyword, <code> create </code>, serves both to introduce creation instructions and the creation clause listing creation procedures at the beginning of the class.
A procedure listed in the creation clause, such as <code> make </code>, otherwise enjoys the same properties as other routines, especially for calls. Here the procedure <code> make </code> is secret since it appears in a clause starting with <code> feature </code> <code> { </code> <code> NONE </code> <code> } </code>; so it would be invalid for a client to include a call such as
<code>acc.make (8_000)</code>
To make such a call valid, it would suffice to move the declaration of <code> make </code> to the first <code> feature </code> clause of class <code> ACCOUNT </code>, which carries no export restriction. Such a call does not create any new object, but simply resets the balance of a previously created account.
==Design by Contract&#153;==
Syntactically, assertions are boolean expressions, with a few extensions such as the <code> old </code>notation. Also, you may split an assertion into two or more clauses, as here with the precondition of <code> withdraw </code>; this is as if you had separated the clauses with an <code> and </code>, but makes the assertion clearer, especially if it includes many conditions.
Assertions play a central part in the Eiffel method for building reliable object-oriented software. They serve to make explicit the assumptions on which programmers rely when they write software elements that they believe are correct. Writing assertions amounts to spelling out the terms of the '''contract''' which governs the relationship between a routine and its callers. The precondition binds the callers; the postcondition binds the routine.
The underlying theory of Design by Contract&#153;, the centerpiece of the Eiffel method, views software construction as based on contracts between clients (callers) and suppliers (routines), relying on mutual obligations and benefits made explicit by the assertions.
==The Contract Form==
Assertions are also an indispensable tool for the documentation of reusable software components: one cannot expect large-scale reuse without a precise documentation of what every component expects (precondition), what it guarantees in return (postcondition) and what general conditions it maintains (invariant).
Documentation tools in EiffelStudio use assertions to produce information for client programmers, describing classes in terms of observable behavior, not implementation. In particular the '''Contract Form''' of a class, also called its "short form", which serves as its interface documentation, is obtained from the full text by removing all non-exported features and all implementation information such as <code> do </code> clauses of routines, but keeping interface information and in particular assertions. Here is the Contract Form of the above class:
<code>
class interface ACCOUNT
create
make
feature
balance: INTEGER
...
deposit (sum: INTEGER) is
-- Deposit sum into the account.
require
sum >= 0
ensure
balance = old balance + sum
withdraw (sum: INTEGER) is
-- Withdraw sum from the account.
require
sum >= 0
sum <= balance - minimum_balance
ensure
balance = old balance - sum
may_withdraw ...
end -- ACCOUNT
</code>
This is not actual Eiffel, only documentation of Eiffel classes, hence the use of slightly different syntax to avoid any confusion ( <code> interface class </code> rather than <code> class </code>). In accordance with the Uniform Access Principle (page [[4 Classes|7]] ), the output for <code> balance </code> would be the same if this feature were a function rather than an attribute.
You will find in EiffelStudio automatic tools to produce the Contract Form of a class. You can also get the '''Flat Contract''' form, based on the same ideas but including inherited features along with those introduced in the class itself. EiffelStudio can produce these forms, and other documentation views of a class, in a variety of output formats including HTML, so that collaborative projects can automatically post the latest versions of their class interfaces on the Internet or an Intranet.
==Contracts for testing and debugging==
Under EiffelStudio you may also set up compilation options, for the whole system or specific classes only, to evaluate assertions at run time, to uncover potential errors ("bugs"). EiffelStudio provides several levels of assertion monitoring: preconditions only, postconditions etc. When monitoring is on, an assertion which evaluates to true has no further effect on the execution. An assertion that evaluates to false will trigger an exception, as described next; unless you have written an appropriate exception handler, the exception will cause an error message and termination with a precise message and a call trace.
This ability to check assertions provides a powerful testing and debugging mechanism, in particular because the classes of the EiffelBase Libraries, widely used in Eiffel software development, are protected by carefully written assertions.
Run-time monitoring, however, is only one application of assertions, whose role as design and documentation aids, as part of theory of Design by Contract&#153;, exerts a pervasive influence on the Eiffel style of software development.

View File

@@ -0,0 +1,22 @@
[[Property:title|2 Design Principles]]
[[Property:link_title|I2E: Design Principles]]
[[Property:weight|-13]]
The aim of Eiffel is to help specify, design, implement and modify quality software. This goal of quality in software is a combination of many factors; the language design concentrated on the three factors which, in the current state of the industry, are in direct need of improvements: reusability, extendibility and reliability. Also important were other factors such as efficiency, openness and portability.
'''Reusability''' is the ability to produce components that may serve in many different applications. Central to the Eiffel approach is the presence of predefined libraries such as EiffelBase, and the language's support for the production of new libraries.
'''Extendibility''' is the ability to produce easily modifiable software. "Soft" as software is supposed to be, it is notoriously hard to modify software systems, especially large ones.
Among quality factors, reusability and extendibility play a special role: satisfying them means having less software to write -- and hence more time to devote to other important goals such as efficiency, ease of use or integrity.
The third fundamental factor is '''reliability, ''' the ability to produce software that is correct and robust -- that is to say, bug-free. Eiffel techniques such as static typing, assertions, disciplined exception handling and automatic garbage collection are essential here.
Three other factors are also part of Eiffel's principal goals: <br/>
* The language enables implementers to produce high '''efficiency''' compilers, so that systems developed with Professional Eiffel may run under speed and space conditions similar to those of programs written in lower-level languages.
* Ensuring '''openness''', so that Eiffel software may cooperate with programs written in other languages.
* Guaranteeing '''portability''' by a platform-independent language definition, so that the same semantics may be supported on many different platforms.

View File

@@ -0,0 +1,41 @@
[[Property:title|8 Event-Driven Programming and Agents]]
[[Property:link_title|I2E: Event-Driven Programming and Agents]]
[[Property:weight|-7]]
The division of roles in object technology is clear: of the two principal constituents of a system, object types and operations, the first dominates. Classes, representing object types, determines the structure of the software; every routine, representing an operations, belongs to a class.
In some circumstances it is useful to define an object that denotes an operation. This is especially useful if you want to build an object structure that refers to operations, so that you can later traverse the structure and execute the operations encountered. A typical application is '''event-driven programming''' for Graphical User Interfaces (GUI), including Web programming. In GUI programming you will want to record properties of the form
<code>
"When the user clicks this OK button, the system must update the file"
</code>
each involves a '''control''' (here the OK button), an '''event''' (mouse click) and an '''operation''' (update the file). This can be programmed by having an "event loop", triggered for each event, which performs massive decision-making ( <code> if </code> <code> "The latest event was `left mouse click on button 23'" </code> <code> then </code> <code> "Appropriate instructions" </code> <code> else if </code>... and so on with many branches); but this leads to bulky software architectures where introducing any new control or event requires updating a central part of the code. It's preferable to let any element of the system that encounters a new control-event-operation association
<code>
[control, event, operation]
</code>
store it as a triple of objects into an object structure, such as an array or a list. Triples in that structure may come from different parts of the system; there is no central know-it-all structure. The only central element is a simple mechanism which can explore the object structure to execute each <code> operation </code> associated with a certain <code> control </code> and a certain <code> event </code>. The mechanism is not just simple; it's also independent of your application, since it doesn't need to know about any particular control, event or operation (it will find them in the object structure). So it can be programmed once and for all, as part of a library such as EiffelVision 2 for platform-independent graphics.
To build an object structure, we need objects. A <code> control </code>, an <code> event </code> are indeed objects. But an <code> operation </code> is not: it's program code -- a routine of a certain class.
Agents address this issue. An agent is an object that represents a routine, which can then be kept in an object structure. The simplest form of agent is written <code> agent </code> <code> r </code>, where <code> r </code> is a routine. This denotes an object. If <code> your_agent </code> is such an agent object, the call
<code>
your_agent.call ([a, b])
</code>
where <code> a </code> and <code> b </code> are valid arguments for <code> r </code>, will have the same effect as a direct call to <code> r </code> with arguments <code> a </code> and <code> b </code>. Of course, if you know that you want to call <code> r </code> with those arguments, you don't need any agents; just use the direct call <code> r </code> <code> ( </code> <code> a, b </code> <code> ) </code>. The benefit of using an agent is that you can store it into an object structure to be called '''later''', for example when an event-driven mechanism finds the agent in the object structure, associated with a certain control and a certain event. For this reason agents are also called '''delayed calls'''.
{{info|The notation <code> [ </code> <code> a, b </code> <code> ] </code> denotes a sequence of elements, or '''tuple'''. The reason <code> call </code> needs a tuple as argument, whereas the direct call <code> r </code> <code> ( </code> <code> a, b </code> <code> ) </code> doesn't, is that <code> call </code> is a general routine (from the EiffelBase class <code> ROUTINE </code>, representing agents) applicable to any agent, whereas the direct call refers explicitly to <code> r </code> and hence requires arguments <code> a </code> and <code> b </code> of specific types. The agent mechanism, however, is statically typed like the rest of the language; when you call <code> call </code>, the type checking mechanism ensures that the tuple you pass as argument contains elements <code> a </code> and <code> b </code> of the appropriate types. }}
A typical use of agents with EiffelVision 2 is
<code>
ok_button.select_actions.extend (agent your_routine)</code>
which says: "add <code> your_routine </code> to the list of operations to be performed whenever a <code> select </code> event (left click) happens on <code> ok_button </code>". <code> ok_button </code>. <code> select_actions </code>is the list of agents associated with the button and the event; in list classes, procedure <code> extend </code> adds an item at the end of a list. Here, the object to be added is the agent.
This enables the EiffelVision event-handling mechanism to find the appropriate agent when it processes an event, and call <code> call </code> on that agent to trigger the appropriate routine. EiffelVision doesn't know that it's <code> your_routine </code>; in fact, it doesn't know anything about your application. It simply finds an agent in the list, and calls <code> call </code> on it. For your part, as the author of a graphical application, you don't need to know how EiffelVision handles events; you simply associate the desired agents with the desired controls and events, and let EiffelVision 2 do the rest.
Agents extend to many areas beyond GUIs. In '''numerical computation''', you may use an agent to pass to an "integrator" object a numerical function to be integrated over a certain interval. In yet another area, you can use agents (as in the iteration library of EiffelBase) to program '''iterators''' : mechanisms that repetitively apply an arbitrary operation -- represented by an agent -- to every element of a list, tree or other object structure. More generally, agent embody properties of the associated routines, opening the way to mechanism for '''reflection''', also called "introspection": the ability, during software execution, to discover properties of the software itself.

View File

@@ -0,0 +1,47 @@
[[Property:title|7 Exceptions]]
[[Property:link_title|I2E: Exceptions]]
[[Property:weight|-8]]
Whenever there is a contract, the risk exists that someone will break it. This is where exceptions come in.
Exceptions -- contract violations -- may arise from several causes. One is an assertion violation, if you've selected run-time assertion monitoring. Another is a signal triggered by the hardware or operating system to indicate an abnormal condition such as arithmetic overflow, or an attempt to create a new object when there's not enough memory available.
Unless a routine has made specific provision to handle exceptions, it will '''fail''' if an exception arises during its execution. This in turn provides one more source of exceptions: a routine that fails triggers an exception in its caller.
A routine may, however, handle an exception through a <code> rescue </code> clause. This optional clause attempts to "patch things up" by bringing the current object to a stable state (one satisfying the class invariant). Then it can terminate in either of two ways:<br/>
* The <code> rescue </code> clause may execute a <code> retry </code> instruction, which causes the routine to restart its execution from the beginning, attempting again to fulfill its contract, usually through another strategy. This assumes that the instructions of the <code> rescue </code> clause, before the <code> retry </code>, have attempted to correct the cause of the exception.
* If the <code> rescue </code> clause does not end with <code> retry </code>, then the routine fails: it returns to its caller, immediately triggering an exception. (The caller's <code> rescue </code> clause will be executed according to the same rules.)
The principle is that '''a routine must either succeed or fail''': it either fulfills its contract, or not; in the latter case it must notify its caller by triggering an exception.
Usually, only a few routines of a system will explicitly include a <code> rescue </code>clause. A routine that doesn't have an explicit <code> rescue </code> is considered to have an implicit one, which calls a routine <code> default_rescue </code> that by default does nothing, so that an exception will cause the routine to fail immediately, propagating the exception to the caller.
An example using the exception mechanism is a routine <code> attempt_transmission </code> that tries to transmit a message over a phone line. The actual transmission is performed by an external, low-level routine <code> transmit </code>; once started, however, <code> transmit </code> may abruptly fail, triggering an exception, if the line is disconnected. Routine <code> attempt_transmission </code> tries the transmission at most 50 times; before returning to its caller, it sets a boolean attribute <code> successful </code> to <code> True </code> <code> or </code> <code> False </code> depending on the outcome. Here is the text of the routine:
<code>
attempt_transmission (message: STRING) is
-- Try to transmit message, at most 50 times.
-- Set successful accordingly.
local
failures: INTEGER
do
if failures < 50 then
transmit (message)
successful := True
else
successful := False
end
rescue
failures := failures + 1
retry
end
</code>
Initialization rules ensure that <code> failures </code>, a local entity, is set to zero on entry.
This example illustrates the simplicity of the mechanism: the <code> rescue </code> clause never attempts to achieve the routine's original intent; this is the sole responsibility of the body (the <code> do </code> clause). The only role of the <code> rescue </code> clause is to clean up the objects involved, and then either to fail or to retry.
This disciplined exception mechanism is essential for software developers, who need protection against unexpected events, but cannot be expected to sacrifice safety and simplicity to pay for this protection.

View File

@@ -0,0 +1,26 @@
[[Property:title|9 Genericity]]
[[Property:link_title|I2E: Genericity]]
[[Property:weight|-6]]
Building software components (classes) as implementations of abstract data types yields systems with a solid architecture but does not in itself ensure reusability and extendibility. Two key techniques address the problem: generosity (unconstrained or constrained) and inheritance. Let us look first at the unconstrained form.
To make a class generic is to give it '''formal generic parameters''' representing as unknown types, as in these examples from EiffelBase, an open-source library covering basic data structures and algorithms:
<code>ARRAY [G]
LIST [G]
LINKED_LIST [G]</code>
These classes describe data structures -- arrays, lists without commitment to a specific representation, lists in linked representation -- containing objects of a certain type. The formal generic parameter <code> G </code> denotes this type.
A class such as these doesn't quite yet describe a type, but a type template, since <code> G </code> itself denotes an unknown type. To derive a directly usable list or array type, you must provide a type corresponding to <code> G </code>, called an '''actual generic parameter'''; this may be either an expanded type, including basic types such as <code> INTEGER </code>, or a reference type. Here are some possible generic derivations:
<code>il: LIST [INTEGER]
aa: ARRAY [ACCOUNT]
aal: LIST [ARRAY [ACCOUNT]]</code>
As the last example indicates, an actual generic parameter may itself be generically derived.
It would not be possible, without genericity, to have static type checking in a realistic object-oriented language.
A variant of this mechanism, constrained genericity, will enable a class to place specific requirements on possible actual generic parameters. Constrained genericity will be described after inheritance.

View File

@@ -0,0 +1,68 @@
[[Property:title|10 Inheritance]]
[[Property:link_title|I2E: Inheritance]]
[[Property:weight|-5]]
Inheritance, the other fundamental generalization mechanism, makes it possible to define a new class by combination and specialization of existing classes rather than from scratch.
The following simple example, from the Data Structure Library in EiffelBase, is typical. <code> LIST </code>, as noted, describes lists in any representation. One such representation if the lists have a fixed number of elements uses an array. We may define the corresponding class by combination of <code> LIST </code> and <code> ARRAY </code>, as follows:
<code>
class ARRAYED_LIST [G]
inherit
LIST [G]
ARRAY [G]
export ... See below ... end
feature
... Specific features of fixed-size lists ...
end -- ARRAYED_LIST
</code>
The <code> inherit </code> ... clause lists all the "parents" of the new class, which is said to be their "heir". (The "ancestors" of a class include the class itself, its parents, grandparents etc.; the reverse term is "descendant".) Declaring <code> ARRAYED_LIST </code> as shown ensures that all the features and properties of lists and arrays are applicable to arrayed lists as well. Since the class has more than one parent, this is a case of multiple inheritance.
Standard graphical conventions -- drawn from the Business Object Notation or BON, a graphical object-oriented notation based on concepts close to those of Eiffel, and directly supported by EiffelStudio -- illustrate such inheritance structures:
[[Image:invitation-4]]
An heir class such as <code> ARRAYED_LIST </code> needs the ability to define its own export policy. By default, inherited features keep their export status (publicly available, secret, available to selected classes only); but this may be changed in the heir. Here, for example, <code> ARRAYED_LIST </code> will export only the exported features of <code> LIST </code>, making those of <code> ARRAY </code> unavailable directly to <code> ARRAYED_LIST </code> 's clients. The syntax to achieve this is straightforward:
<code>
class ARRAYED_LIST [G]
inherit
LIST [G]
ARRAY [G]
export {NONE} all end
... The rest as above ...
</code>
Another example of multiple inheritance comes from a windowing system based on a class <code> WINDOW </code>, close to actual classes in EiffelVision 2. Windows have '''graphical''' features: a height, a width, a position, routines to scale windows, move them, and other graphical operations. The system permits windows to be nested, so that a window also has '''hierarchical''' features: access to sub windows and the parent window, adding a sub window, deleting a sub window, attaching to another parent and so on. Rather than writing complex class that would contain specific implementations for all of these features, it is preferable to inherit all hierarchical features from <code> TREE </code> (a class in EiffelBase describing trees), and all graphical features from a class <code> RECTANGLE </code>.
Inheritance complements the "client" relation by providing another form of reuse that yields remarkable economies of effort -- for analysis, design, implementation, evolution -- and has a profound effect on the entire software development process.
The very power of inheritance demands adequate means to keep it under control. Multiple inheritance, in particular, raises the question of name conflicts between features inherited from different parents; this case will inevitably arise in practice, especially for classes contributed by independent developers. You may remove such a name conflict through '''renaming''', as in
<code>
class C
inherit
A
rename
x as x1,
y as y1
end
B
rename
x as x2,
y as y2
end
feature ...
</code>
Here, if both <code> A </code> and <code> B </code> have features named <code> x </code> and <code> y </code>, class <code> C </code> would be invalid without the renaming.
Renaming also serves to provide more appropriate feature names in descendants. For example, class <code> WINDOW </code> may inherit a routine <code> insert_subtree </code> from <code> TREE </code>. For clients of <code> WINDOW </code>, however, such a routine name is no longer appropriate. An application that uses this class needs coherent window terminology, and should have to concern itself with the inheritance structure that led to the class. So you may wish to rename <code> insert_subtree </code> as <code> add_subwindow </code> in the inheritance clause of <code> WINDOW </code>.
As a further protection against misusing multiple inheritance, the invariants of all parent classes automatically apply to a newly defined class. So classes may not be combined if their invariants are incompatible.

View File

@@ -0,0 +1,65 @@
[[Property:title|11 Polymorphism and Dynamic Binding]]
[[Property:link_title|I2E: Polymorphism and Dynamic Binding]]
[[Property:weight|-4]]
Inheritance is not just a module combination and enrichment mechanism. It also enables the definition of flexible entities that may become attached to objects of various forms at run time, a property known as polymorphism.
This remarkable facility must be reconciled with static typing. The language convention is simple: an assignment of the form <code> a </code> <code> : </code> <code> b </code> is permitted not only if <code> a </code> and <code> b </code> are of the same type, but more generally if <code> a </code> and <code> b </code> are of reference types <code> A </code> and <code> B </code>, based on classes <code> A </code> and <code> B </code> such that <code> B </code> is a descendant of <code> A </code>.
This corresponds to the intuitive idea that a value of a more specialized type may be assigned to an entity of a less specialized type -- but not the reverse. (As an analogy, consider that if you request vegetables, getting green vegetables is fine, but if you ask for green vegetables, receiving a dish labeled just "vegetables" is not acceptable, as it could include, say, carrots.)
What makes this possibility particularly powerful is the complementary facility: '''feature redefinition'''. A class may redefine some or all of the features which it inherits from its parents. For an attribute or function, the redefinition may affect the type, replacing the original by a descendant; for a routine it may also affect the implementation, replacing the original routine body by a new one.
Assume for example a class <code> POLYGON </code>, describing polygons, whose features include an array of points representing the vertices and a function <code> perimeter </code> which computes a polygon's perimeter by summing the successive distances between adjacent vertices. An heir of <code> POLYGON </code> may begin as:
<code>
class RECTANGLE
inherit
POLYGON
redefine
perimeter
end
feature -- Specific features of rectangles, such as:
side1: REAL
side2: REAL
perimeter: REAL is
-- Rectangle-specific version
do
Result := 2 * (side1 + side2)
end
... Other RECTANGLE features ...
</code>
Here it is appropriate to redefine <code> perimeter </code> for rectangles as there is a simpler and more efficient algorithm. Note the explicit <code> redefine </code> sub clause (which would come after the <code> rename </code> if present).
Other descendants of <code> POLYGON </code> may also have their own redefinitions of <code> perimeter </code>. The version to use in any call is determined by the run-time form of the target. Consider the following class fragment:
<code>p: POLYGON; r: RECTANGLE
... create p; create r ...
if c then
p := r
end
print (p.perimeter)</code>
The polymorphic assignment <code> p </code> := <code> r </code> is valid because of the above rule. If condition <code> c </code> is false, <code> p </code> will be attached to an object of type <code> POLYGON </code> for the computation of <code> p </code>. <code> perimeter </code>, which will thus use the polygon algorithm. In the opposite case, however, <code> p </code> will be attached to a rectangle; then the computation will use the version redefined for <code> RECTANGLE </code>. This is known as '''dynamic binding'''.
Dynamic binding provides a high degree of flexibility. The advantage for clients is the ability to request an operation (such as perimeter computation) without explicitly selecting one of its variants; the choice only occurs at run-time. This is essential in large systems, where many variants may be available; dynamic binding protects each component against changes in other components.
This technique is particularly attractive when compared to its closest equivalent in traditional approaches, where you would need records with variant components, or union types (C), together with <code> case </code> (switch) instructions to discriminate between variants. This means that every client must know about every possible case, and that any extension may invalidate a large body of existing software.
The combination of inheritance, feature redefinition, polymorphism and dynamic binding supports a development mode in which every module is open and incremental. When you want to reuse an existing class but need to adapt it to a new context, you can define a new descendant of that class (with new features, redefined ones, or both) without any change to the original. This facility is of great importance in software development, an activity that -- by design or circumstance -- is invariably incremental.
The power of these techniques demands adequate controls. First, feature redefinition, as seen above, is explicit. Second, because the language is typed, a compiler can check statically whether a feature application <code> a </code>. <code> f </code> is correct. In contrast, dynamically typed object-oriented languages defer checks until run-time and hope for the best: if an object "sends a message" to another (that is to say, calls one of its routines) one just expects that the corresponding class, or one of its ancestors, will happen to include an appropriate routine; if not, a run-time error will occur. Such errors will not happen during the execution of a type-checked Eiffel system.
In other words, the language reconciles dynamic binding with static typing. Dynamic binding guarantees that whenever more than one version of a routine is applicable the right version (the one most directly adapted to the target object) will be selected. Static typing means that the compiler makes sure there is at least one such version.
This policy also yields an important performance benefit: in contrast with the costly run-time searches that may be needed with dynamic typing (since a requested routine may not be defined in the class of the target object but inherited from a possibly remote ancestor), the EiffelStudio implementation always finds the appropriate routine in constant-bounded time.
Assertions provide a further mechanism for controlling the power of redefinition. In the absence of specific precautions, redefinition may be dangerous: how can a client be sure that evaluation of <code> p </code>. <code> perimeter </code> will not in some cases return, say, the area? Preconditions and postconditions provide the answer by limiting the amount of freedom granted to eventual redefiners. The rule is that any redefined version must satisfy a weaker or equal precondition and ensure a stronger or equal postcondition than in the original. This means that it must stay within the semantic boundaries set by the original assertions.
The rules on redefinition and assertions are part of the Design by Contract&#153; theory, where redefinition and dynamic binding introduce subcontracting. <code> POLYGON </code>, for example, subcontracts the implementation of perimeter to <code> RECTANGLE </code> when applied to any entity that is attached at run-time to a rectangle object. An honest subcontractor is bound to honor the contract accepted by the prime contractor. This means that it may not impose stronger requirements on the clients, but may accept more general requests: weaker precondition; and that it must achieve at least as much as promised by the prime contractor, but may achieve more: stronger postcondition.

View File

@@ -0,0 +1,34 @@
[[Property:title|14 Putting a System Together]]
[[Property:link_title|I2E: Putting a System Together]]
[[Property:weight|-1]]
We have now studied the constituents of Eiffel software. It remains to see how you can combine these elements into executable '''systems''' (the Eiffel concept closest to the traditional notion of program) and libraries.
How do you get an executable system? All you need is to <br/>
* Provide a set of classes, called a '''universe'''.
* Designate one of these classes as the '''root class'''.
* Designate one of its creation procedures as the '''root procedure'''.
This defines what it means to execute the system: create one direct instance of the root class (the execution's '''root object'''); and call the root procedure on it. That's all.
In any practical case, the root procedure will create other objects, call other routines on them, leading to further creations and calls.
For the system to be valid, it must include all the classes which the root '''needs''' directly or indirectly; a class "needs" another if it is one of its heirs or clients.
For a library we don't need to specify a root. If we want to make sure that every class in a library compiles fine we can specify that we want all classes to be the root.
The Eiffel method suggests grouping related classes (typically 5 to 40 classes) into collections called '''clusters'''. A universe is then a set of clusters. For example the EiffelBase library is divided into clusters corresponding each to a major category of data structure: <code> lists </code>, <code> tables </code>, <code> iteration </code> and so on. You can nest clusters, using for example EiffelBase, with its own subclusters as listed, as a cluster of your system.
How will you specify a universe? Any Eiffel implementation can use its own conventions. EiffelStudio applies a simple policy: <br/>
* Store each class in a single file, called its class file, with a name of the form <code> name </code> . <code> e </code>. For clarity, <code> name </code> should be the lower-case version of the class name, although this is a style rule, not a requirement.
* Put all the class files of a cluster into a single directory (folder on Windows), called its cluster directory.
{{note|It is desirable for clarity, as a style rule, to separate clusters that directly contain classes ("terminal clusters") from those that have subclusters. Cluster directories will then contain class files or cluster subdirectories, but not both. }}
* To specify a system, it suffices to provide a list of cluster directories, along with the name of the root class and root procedure. The universe consists of the classes contained in all the class files in the listed cluster directories.
Such a system specification is written in an ecf (eiffel configuration file) which is an xml based file format. It can be created by using the project settings in EiffelStudio.

View File

@@ -0,0 +1,20 @@
[[Property:title|5 Types]]
[[Property:link_title|I2E: Types]]
[[Property:weight|-10]]
Eiffel is strongly typed for readability and reliability. Every entity is declared of a certain type, which may be either a reference type or an expanded type.
Any type <code> T </code> is based on a class, which defines the operations that will be applicable to instances of <code> T </code>. The difference between the two categories of type affects the semantics of an entity <code> x </code> declared of type <code> T </code>: for a reference type, the most common case, possible values for <code> x </code> are references to objects; for an expanded type, the values are objects. In both cases, the type rules guarantee that the objects will be instances of <code> T </code>.
A non-expanded class such as <code> ACCOUNT </code> yields a reference type. As a result, an entity of type <code> ACCOUNT </code>, such as <code> acc </code> in the earlier client example (see the declaration of <code> acc </code> and the accompanying picture as given on page [[Invitation to Eiffel|6]] ), denotes possible run-time references to objects of type <code> ACCOUNT </code>.
In contrast, the value of an entity <code> acc </code> declared of type <code> expanded </code> <code> ACCOUNT </code> is an object such as the one shown on the figure below, with no reference. The only difference with the earlier figure is that the value of <code> acc </code> is now an <code> ACCOUNT </code> object, not a reference to such an object. No creation instruction is needed in this case. (The figure does not show the <code> PERSON </code> object to which the <code> owner </code> field of the <code> ACCOUNT </code> object -- itself a reference -- is attached.)
[[Image:invitation-3]]
An important group of expanded types, based on library classes, includes the basic types <code> CHARACTER, DOUBLE, REAL, INTEGER </code> and <code> BOOLEAN </code>. Clearly, the value of an entity declared of type <code> INTEGER </code> should be an integer, not a reference to an object containing an integer value. Operations on these types are defined by prefix and infix operators such as "+" and "<".
As a result of these conventions, the type system is uniform and consistent: all types, including the basic types, are defined from classes, either as reference types or as expanded types.
In the case of basic types, for obvious reasons of efficiency, the compilation mechanism implements the standard arithmetic and boolean operations directly through the corresponding machine operations, not through routine calls. But this is only a compiler optimization, which does not hamper the conceptual homogeneity of the type edifice.

View File

@@ -0,0 +1,10 @@
[[Property:title|1 What Must I Know First?]]
[[Property:link_title|I2E: What Must I Know First?]]
[[Property:weight|-14]]
This Invitation assumes that you have some experience of software development, but that's all. Previous exposure to object technology is not required. If you've had it, it will help; but if it has all been to notations like UML or programming languages like C++ and Java, you should not let it guide your study of this Invitation. Although Eiffel shares a number of properties with these other approaches, it takes a fresh path to object technology, based on a small number of simple, far-reaching concepts.
Once you are familiar with the basic ideas you may want to try them with EiffelStudio, which provides a direct implementation of the Eiffel concepts, available in a completely portable way across Windows, Linux, many versions of Unix and VMS.

View File

@@ -0,0 +1,39 @@
[[Property:title|Invitation to Eiffel]]
[[Property:weight|-15]]
==Interactive Software Engineering==
[[MANUAL IDENTIFICATION AND COPYRIGHT: Invitation|MANUAL IDENTIFICATION AND COPYRIGHT]]
{{note| This is '''not''' an introduction to the EiffelStudio development environment. See the [[Getting started with Eiffel| list of introductory documents ]] for a Guided Tour of EiffelStudio and a detailed Eiffel Tutorial. }}
==[[1 What Must I Know First?|1 WHAT MUST I KNOW FIRST?]]==
==[[2 Design Principles|2 DESIGN PRINCIPLES]]==
==[[3 Object-Oriented Design|3 OBJECT-ORIENTED DESIGN]]==
==[[4 Classes|4 CLASSES ]]==
==[[5 Types|5 TYPES ]]==
==[[6 Design by Contract and Assertions|6 DESIGN BY CONTRACT AND ASSERTIONS]]==
==[[7 Exceptions|7 EXCEPTIONS]]==
==[[8 Event-Driven Programming and Agents|8 EVENT-DRIVEN PROGRAMMING AND AGENTS]]==
==[[9 Genericity|9 GENERICITY]]==
==[[10 Inheritance|10 INHERITANCE ]]==
==[[11 Polymorphism and Dynamic Binding|11 POLYMORPHISM AND DYNAMIC BINDING ]]==
==[[12 Combining Genericity and Inheritance|12 COMBINING GENERICITY AND INHERITANCE ]]==
==[[13 Deferred Classes and Seamless Development|13 DEFERRED CLASSES AND SEAMLESS DEVELOPMENT]]==
==[[14 Putting a System Together|14 PUTTING A SYSTEM TOGETHER]]==