Author:halw

Date:2008-10-20T22:11:16.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@90 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
halw
2008-10-20 22:11:16 +00:00
parent 79cb135596
commit c9ad246db9
4 changed files with 553 additions and 501 deletions

View File

@@ -1,6 +1,20 @@
[[Property:title|Community]]
[[Property:weight|2]]
[[Property:uuid|75c75712-7c3e-2757-51b7-77b404471e2e]]
The Community book is a vehicle through which community members will be able to submit and/or revise documentation content.
EiffelStudio community:
:'''You can become a contributor!'''
EiffelStudio documentation is available in a convenient Wiki format. This makes it possible to improve the documentation continuously and make sure it is always up to date.
Community input is welcome. If you are interested in improving and developing EiffelStudio documentation, you can become:
* A contributor: authorized to edit existing pages to any book, and to add pages to the "Community contributions" book.
**"Community contributions" book pages can be added to other books by an editor.
* An editor: authorized to modify and add pages in any book.
To become a contributor, you should be proficient in Eiffel technology and have good written English skills. To become an editor, you should already be a contributor and have contributed significant improvements or additions to the documentation.
If you are interested in becoming a contributor, please send an email to info@eiffel.com with a short description of your Eiffel experience and any other relevant background.

View File

@@ -9,6 +9,8 @@ Eiffel directly implements the ideas of Design by Contract™ , which enhance
A system -- a software system in particular, but the ideas are more general -- is made of a number of cooperating components. Design by Contract™ states that their cooperation should be based on precise specifications -- contracts -- describing each party's expectations and guarantees.
An Eiffel contract is similar to a real-life contract between two people or two companies, which it is convenient to express in the form of tables listing the expectations and guarantees. Here for example is how we could sketch the contract between a homeowner and the telephone company:
{| border="1"
|-
| style="width=10%" |provide telephone service
@@ -28,6 +30,7 @@ Provide telephone service.
No need to provide anything if bill not paid.
|}
Note how the obligation for each of the parties maps onto a benefit for the other. This will be a general pattern.
The client's obligation, which protects the supplier, is called a '''precondition'''. It states what the client must satisfy before requesting a certain service. The client's benefit, which describes what the supplier must do (assuming the precondition was satisfied), is called a '''postcondition'''.
@@ -36,50 +39,50 @@ In addition to preconditions and postconditions, contract clauses include '''cla
==Expressing assertions==
Eiffel provides syntax for expressing preconditions ( <code>require</code>), postconditions ( <code>ensure</code>) and class invariants ( <code>invariant</code>), as well as other assertion constructs studied later (see [[10 Other Mechanisms|"Instructions", page 84]] ): loop invariants and variants, check instructions.
Eiffel provides syntax for expressing preconditions (<code>require</code>), postconditions (<code>ensure</code>) and class invariants (<code>invariant</code>), as well as other assertion constructs studied later (see [[10 Other Mechanisms#Instructions|"Instructions"]] ): loop invariants and variants, check instructions.
Here is a partial update of class <code>ACCOUNT</code> with more assertions:
<code>
indexing
description: "Simple bank accounts"
description: "Simple bank accounts"
class
ACCOUNT
ACCOUNT
feature -- Access
balance: INTEGER
-- Current balance
balance: INTEGER
-- Current balance
deposit_count: INTEGER is
-- Number of deposits made since opening
do
... As before ...
end
deposit_count: INTEGER
-- Number of deposits made since opening
do
... As before ...
end
feature -- Element change
deposit (sum: INTEGER) is
-- Add `sum' to account.
require
non_negative: sum >= 0
do
... As before ...
ensure
one_more_deposit: deposit_count = old deposit_count + 1
updated: balance = old balance + sum
end
deposit (sum: INTEGER)
-- Add `sum' to account.
require
non_negative: sum >= 0
do
... As before ...
ensure
one_more_deposit: deposit_count = old deposit_count + 1
updated: balance = old balance + sum
end
feature {NONE} -- Implementation
all_deposits: DEPOSIT_LIST
-- List of deposits since account's opening.
all_deposits: DEPOSIT_LIST
-- List of deposits since account's opening.
invariant
consistent_balance: (all_deposits /= Void) implies
(balance = all_deposits . total)
zero_if_no_deposits: (all_deposits = Void) implies
(balance = 0)
consistent_balance: (all_deposits /= Void) implies
(balance = all_deposits . total)
zero_if_no_deposits: (all_deposits = Void) implies
(balance = 0)
end -- class ACCOUNT
</code>
@@ -93,6 +96,8 @@ The precondition of a routine expresses conditions that the routine is imposing
The postcondition of a routine expresses what the routine guaranteed to its clients for calls satisfying the precondition. The notation <code>old expression</code>, valid in postconditions ( <code>ensure</code> clauses) only, denotes the value that <code>expression</code> had on entry to the routine.
The precondition and postcondition state the terms of the contract between the routine and its clients, similar to the earlier example of a human contract:
{| border="1"
|-
| style="width=10%" |<code>deposit</code>
@@ -112,18 +117,21 @@ Update deposits list and balance.
No need to handle negative arguments.
|}
The class invariant, as noted, applies to all features. It must be satisfied on exit by any creation procedure, and is implicitly added to both the precondition and postcondition of every exported routine. In this respect it is both good news and bad news for the routine implementer: good news because it guarantees that the object will initially be in a stable state, averting the need in the example to check that the total of <code>all_deposits</code> is compatible with the <code>balance</code>; bad news because, in addition to its official contract as expressed by its specific postcondition, every routine must take care of restoring the invariant on exit.
A requirement on meaningful contracts is that they should be in good faith: satisfiable by an honest partner. This implies a consistency rule: if a routine is exported to a client (either generally or selectively), any feature appearing in its precondition must also be available to that client. Otherwise -- for example if the precondition included <code>require n > 0</code>, where <code>n</code> is a secret attribute -- the supplier would be making demands that a good-faith client cannot possibly check for.
Note in this respect that guaranteeing a precondition does not necessarily mean, for the client, testing for it. Assuming <code>n</code> is exported, a call may test for the precondition
<code>
if x.n > 0 then x.r end
if x.n > 0 then
x.r
end
</code>
possibly with an <code>else</code> part. But if the context of the call, in the client's code, implies that <code>n</code> is positive -- perhaps because some preceding call set it to the sum of two squares -- then there is no need for an <code>if</code> or similar construct.
{{note|In such a case, a <code>check</code> instruction as introduced later ( [[10 Other Mechanisms|"Instructions", page 84]] ) is recommended if the reason for omitting the test is non-trivial. }}
{{note|In such a case, a <code>check</code> instruction as introduced later ( [[10 Other Mechanisms#Instructions|"Instructions"]] ) is recommended if the reason for omitting the test is non-trivial. }}
==Using contracts for built-in reliability==
@@ -137,28 +145,27 @@ Contracts in Eiffel are not just wishful thinking. They can be monitored at run
It should be clear from the preceding discussion that contracts are not a mechanism to test for special conditions, for example erroneous user input. For that purpose, the usual control structures ( <code>if deposit_sum > 0 then</code> ...) are available, complemented in applicable cases by the exception handling mechanism reviewed next. An assertion is instead a '''correctness condition''' governing the relationship between two software modules (not a software module and a human, or a software module and an external device). If <code>sum</code> is negative on entry to <code>deposit</code>, violating the precondition, the culprit is some other software element, whose author was not careful enough to observe the terms of the deal. Bluntly:
{{note| '''Assertion Violation rule '''A run-time assertion violation is the manifestation of a bug. }}
{{rule|name=Assertion Violation|text=A run-time assertion violation is the manifestation of a bug. }}
To be more precise: <br/>
* A precondition violation signals a bug in the client, which did not observe its part of the deal.
* A postcondition (or invariant) violation signals a bug in the supplier -- the routine -- which did not do its job.
That violations indicate bugs explains why it is legitimate to enable or disable assertion monitoring through mere compilation options: for a correct system -- one without bugs -- assertions will always hold, so the compilation option makes no difference to the semantics of the system.
But of course for an incorrect system the best way to find out where the bug is -- or just that there is a bug -- is often to monitor the assertions during development and testing. Hence the presence of the compilation options, which EiffelStudio lets you set separately for each class, with defaults at the system and cluster levels: <br/>
* <code>no</code> : assertions have no run-time effect.
* <code>require</code> : monitor preconditions only, on routine entry.
* <code>ensure</code> : preconditions on entry, postconditions on exit.
* <code>invariant</code> : like <code>ensure</code>, plus class invariant on both entry and exit for qualified calls.
* <code>all</code> : like <code>invariant</code>, plus <code>check</code> instructions, loop invariants and loop variants ( [[10 Other Mechanisms|"Exception handling", page 46]] ).
* <code>invariant</code> : same as <code>ensure</code>, plus class invariant on both entry and exit for qualified calls.
* <code>all</code> : same as <code>invariant</code>, plus <code>check</code> instructions, loop invariants and loop variants.
An assertion violation, if detected at run time under one of these options other than the first, will cause an exception ( [[8 Design by Contract (tm), Assertions and Exceptions|"Instructions", page 84]] ). Unless the software has an explicit "retry" plan as explained in the discussion of exceptions, the violation will cause produce an exception trace and cause termination (or, in EiffelStudio, a return to the environment's browsing and debugging facilities at the point of failure). If present, the label of the violated sub clause will be displayed, to help identify the problem.
An assertion violation, if detected at run time under one of these options other than the first, will cause an exception ( [[8 Design by Contract (tm), Assertions and Exceptions#exception_handling|"Exception handling"]] ). Unless the software has an explicit "retry" plan as explained in the discussion of exceptions, the violation will cause produce an exception trace and cause termination (or, in EiffelStudio, a return to the environment's browsing and debugging facilities at the point of failure). If present, the label of the violated sub clause will be displayed, to help identify the problem.
The default is <code>require</code>. This is particularly interesting in connection with the Eiffel method's insistence on reuse: with libraries such as EiffelBase, richly equipped with preconditions expressing terms of use, an error in the '''client software''' will often lead, for example through an incorrect argument, to violating one of these preconditions. A somewhat paradoxical consequence is that even an application developer who does not apply the method too well (out of carelessness, haste, indifference or ignorance) will still benefit from the presence of contracts in someone else's library code.
During development and testing, assertion monitoring should be turned on at the highest possible level. Combined with static typing and the immediate feedback of compilation techniques such as the Melting Ice Technology, this permits the development process mentioned in the section [[3 The Software Process in Eiffel|"Quality and functionality", page 10]] , where errors are exterminated at birth. No one who has not practiced the method in a real project can imagine how many mistakes are found in this way; surprisingly often, a violation will turn out to affect an assertion that was just included for goodness' sake, the developer being convinced that it could never "possibly" fail to be satisfied.
During development and testing, assertion monitoring should be turned on at the highest possible level. Combined with static typing and the immediate feedback of compilation techniques such as the Melting Ice Technology, this permits the development process mentioned in the section [[3 The Software Process in Eiffel#Quality_and_functionality|"Quality and functionality"]] , where errors are exterminated at birth. No one who has not practiced the method in a real project can imagine how many mistakes are found in this way; surprisingly often, a violation will turn out to affect an assertion that was just included for goodness' sake, the developer being convinced that it could never "possibly" fail to be satisfied.
By providing a precise reference (the description of what the software is supposed to do) against which to assess the reality (what the software actually does), Design by Contract&#153; profoundly transforms the activities of debugging, testing and quality assurance.
@@ -169,31 +176,31 @@ When releasing the final version of a system, it is usually appropriate to turn
Another application of assertions governs documentation. Environment mechanisms, such as clicking the <code>Form Contract</code> icon in Eiffelstudio, will produce, from a class text, an abstracted version which only includes the information relevant for client authors. Here is the contract form of class <code>ACCOUNT</code> in the latest version given:
<code>
indexing
description: "Simple bank accounts"
description: "Simple bank accounts"
class interface
ACCOUNT
ACCOUNT
feature -- Access
balance: INTEGER
-- Current balance
balance: INTEGER
-- Current balance
deposit_count: INTEGER
-- Number of deposits made since opening
deposit_count: INTEGER
-- Number of deposits made since opening
feature -- Element change
deposit (sum: INTEGER)
-- Add `sum' to account.
require
non_negative: sum >= 0
ensure
one_more_deposit: deposit_count = old deposit_count + 1
updated: balance = old balance + sum
deposit (sum: INTEGER)
-- Add `sum' to account.
require
non_negative: sum >= 0
ensure
one_more_deposit: deposit_count = old deposit_count + 1
updated: balance = old balance + sum
invariant
consistent_balance: balance = all_deposits.total
consistent_balance: balance = all_deposits.total
end -- class interface ACCOUNT
</code>
@@ -202,25 +209,25 @@ The words <code>interface class</code> are used instead of just <code>class</cod
Compared to the full text, the Contract Form of a class (also called its "short form") retains all its interface properties, relevant to client authors: <br/>
* Names and signatures (argument and result type information) for exported features.
* Header comments of these features, which carry informal descriptions of their purpose. (Hence the importance, mentioned in section [[4 Hello World|4]] , of always including such comments and writing them carefully.)
* Header comments of these features, which carry informal descriptions of their purpose. (Hence the importance, mentioned in section [[4 Hello World|"Hello World"]], of always including such comments and writing them carefully.)
* Preconditions and postconditions of these features (at least the subclauses involving only exported features).
* Class invariant (same observation).
The following elements, however, are not in the Contract Form: any information about non-exported features; all the routine bodies ( <code>do</code> clauses, or the <code>external</code> and <code>once</code> variants seen in [[5 The Static Picture: System Organization|"External software", page 16]] above and [[10 Other Mechanisms|"Once routines and shared objects", page 82]] below); assertion subclauses involving non-exported features; and some keywords not useful in the documentation, such as <code>is</code> for a routine.
The following elements, however, are not in the Contract Form: any information about non-exported features; all the routine bodies (<code>do</code> clauses, or the <code>external</code> and <code>once</code> variants seen in [[5 The Static Picture: System Organization#External_software|"External software"]] above and [[10 Other Mechanisms#Once_routines_and_shared_objects|"Once routines and shared objects"]] below); assertion subclauses involving non-exported features; and some keywords not useful in the documentation.
In accordance with the Uniform Access principle (page [[6 The Dynamic Structure: Execution Model|19]] ), the Contract Form does not distinguish between attributes and argument-less queries. In the above example, <code>balance</code> could be one or the other, as it makes no difference to clients, except possibly for performance.
In accordance with the Uniform Access principle (described in [[6 The Dynamic Structure: Execution Model|"Objects, fields, values, and references"]] ), the Contract Form does not distinguish between attributes and argument-less queries. In the above example, <code>balance</code> could be one or the other, as it makes no difference to clients, except possibly for performance.
The Contract Form is the fundamental tool for using supplier classes in the Eiffel method. It enables client authors to reuse software elements without having to read their source code. This is a crucial requirement in large-scale industrial developments.
The Contract Form satisfies two key requirements of good software documentation: <br/>
* It is truly abstract, free from the implementation details of what it describes and concentrating instead on its functionality.
* Rather than being developed separately -- an unrealistic requirement, hard to impose on developers initially and becoming impossible in practice if we expect the documentation to remain up to date as the software evolves -- the documentation is extracted from the software itself. It is not a separate product but a different view of the same product. This prolongs the '''Single Product''' principle that lies at the basis of Eiffel's seamless development model (section [[3 The Software Process in Eiffel|3]] ).
* Rather than being developed separately -- an unrealistic requirement, hard to impose on developers initially and becoming impossible in practice if we expect the documentation to remain up to date as the software evolves -- the documentation is extracted from the software itself. It is not a separate product but a different view of the same product. This prolongs the '''Single Product''' principle that lies at the basis of Eiffel's seamless development model (shown in [[3 The Software Process in Eiffel|"The Software Process in Eiffel"]] ).
The Contract Form is only one of the relevant views. EiffelStudio, for example, generates graphical representations of system structures, to show classes and their relations -- client, inheritance -- according to the conventions of BON (the Business Object Notation). In accordance with the principles of seamlessness and reversibility, EiffelStudio lets you both work on the text, producing the graphics on the fly, or work on the graphics, updating the text on the fly; you can alternate as you wish between these two modes. The resulting process is quite different from more traditional approaches based on separate tools: an analysis and CASE workbench, often based on UML, to deal with an initial "bubble-and-arrow" description; and a separate programming environment, to deal with implementation aspects only. In Eiffel the environment provides consistent, seamless support from beginning to end.
The Contract Form -- or its variant the Flat-Contract Form, which takes account of inheritance ( [[9 Inheritance|"Flat and Flat-Contract Forms", page 72]] ) are the standard form of library documentation, used extensively, for example, in the book <span> [http://www.eiffel.com/doc/page.html Reusable Software] </span> (see bibliography). Assertions play a central role in such documentation by expressing the terms of the contract. As demonstrated a contrario by the widely publicized $500-million crash of the Ariane-5 rocket launcher in June of 1996, due to the incorrect reuse of a software module from the Ariane-4 project, '''reuse without a contract documentation''' is the path to disaster. Non-reuse would, in fact, be preferable.
The Contract Form -- or its variant the Flat-Contract Form, which takes account of inheritance ( [[9 Inheritance#Flat_and_Flat-Contract_Forms|"Flat and Flat-Contract Forms"]] ) are the standard form of library documentation, used extensively, for example, in the book <span> [http://www.eiffel.com/doc/page.html Reusable Software] </span> (see bibliography). Assertions play a central role in such documentation by expressing the terms of the contract. As demonstrated a contrario by the widely publicized $500-million crash of the Ariane-5 rocket launcher in June of 1996, due to the incorrect reuse of a software module from the Ariane-4 project, '''reuse without a contract documentation''' is the path to disaster. Non-reuse would, in fact, be preferable.
==Exception handling==
@@ -232,27 +239,28 @@ Another application of Design by Contract&#153; governs the handling of unexpect
* As a result the routine may fail too -- causing an exception in its own caller.
Note the precise definitions of the two key concepts, failure and exception. Although failure is the more basic one -- since it is defined for atomic, non-routine operations -- the definitions are mutually recursive, since an exception may cause a failure of the recipient routine, and a routine's failure causes an exception in its own caller.
Why state that an exception "may" cause a failure? It is indeed possible to "rescue" a routine from failure in the case of an exception, by equipping it with a clause labeled <code>rescue</code>, as in:
<code>
read_next_character (f: FILE) is
-- Make next character available in last_character.
-- If impossible, set failed to True.
require
readable: file.readable
local
impossible: BOOLEAN
do
if impossible then
failed := True
else
last_character := low_level_read_function (f)
end
rescue
impossible := True
retry
end
read_next_character (f: FILE)
-- Make next character available in last_character.
-- If impossible, set failed to True.
require
readable: file.readable
local
impossible: BOOLEAN
do
if impossible then
failed := True
else
last_character := low_level_read_function (f)
end
rescue
impossible := True
retry
end
</code>
This example includes the only two constructs needed for exception handling: <code>rescue</code> and <code>retry</code>. A <code>retry</code> instruction is only permitted in a rescue clause; its effect is to start again the execution of the routine, without repeating the initialization of local entities (such as <code>impossible</code> in the example, which was initialized to <code>False</code> on first entry). Features <code>failed</code> and <code>last_character</code> are assumed to be attributes of the enclosing class.
@@ -261,42 +269,42 @@ This example is typical of the use of exceptions: as a last resort, for situatio
A variant would be
<code>
local
attempts: INTEGER
do
if attempts < Max_attempts then
last_character := low_level_read_function (f)
else
failed := True
end
rescue
attempts := attempts + 1
retry
end
local
attempts: INTEGER
do
if attempts < Max_attempts then
last_character := low_level_read_function (f)
else
failed := True
end
rescue
attempts := attempts + 1
retry
end
</code>
which would try again up to <code>Max_attempts</code> times before giving up.
The above routine, in either variant, never fails: it always fulfills its contract, which states that it should either read a character or set <code>failed</code> to record its inability to do so. In contrast, consider the new variant
<code>
local
attempts: INTEGER
do
last_character := low_level_read_function (f)
rescue
attempts := attempts + 1
if attempts < Max_attempts then
retry
end
end
local
attempts: INTEGER
do
last_character := low_level_read_function (f)
rescue
attempts := attempts + 1
if attempts < Max_attempts then
retry
end
end
</code>
with no more role for <code>failed</code>. In this case, after <code>Max_attempts</code> unsuccessful attempts, the routine will execute its <code>rescue</code> clause to the end, with no <code>retry</code> (the <code>if</code> having no <code>else</code> clause). This is how a routine '''fails'''. It will, as noted, pass on the exception to its caller.
Such a rescue clause should, before terminating, restore the invariant of the class so that the caller and possible subsequent <code>retry</code>attempts from higher up find the objects in a consistent state. As a result, the rule for an absent <code>rescue</code> clause -- the case for the vast majority of routines in most systems -- is that it is equivalent to
<code>
rescue
default_rescue
rescue
default_rescue
</code>
where procedure <code>default_rescue</code> comes from <code>ANY</code>, where it is defined to do nothing; in a system built for robustness, classes subject to non-explicitly-rescued exceptions should redefine <code>default_rescue</code> (perhaps using a creation procedure, which is bound by the same formal requirement) so that it will always restore the invariant.
@@ -311,13 +319,13 @@ Concretely, exceptions may result from the following events: <br/>
* Operating system signal:arithmetic overfolow; no memory available for a requested creation or clone -- even after garbage collection has rummaged everything to find some space. (But no C/C++-like "wrong pointer address", which cannot occur thanks to the statically typed nature of Eiffel.)
It is sometimes useful, when handling exceptions in <code>rescue</code> clauses, to ascertain the exact nature of the exception that got the execution there. For this it is suffices to inherit from the Kernel Library class <code>EXCEPTIONS</code>, which provides queries such as <code>exception</code>, giving the code for the last exception, and symbolic names ( [[10 Other Mechanisms|"Constant and unique attributes", page 83]] ) for all such codes, such as <code>No_more_memory</code>. You can then process different exceptions differently by testing <code>exception</code> against various possibilities. The method strongly suggests, however, that exception handling code should remain simple; a complicated algorithm in a <code>rescue</code> clause is usually a sign that the mechanism is being misused. Class <code>EXCEPTIONS</code> also provides various facilities for fine-tuning the exception facilities, such as a procedure <code>raise</code> that will explicitly trigger a "developer exception" with a code than can then be detected and processed. Exception handling helps produce Eiffel software that is not just correct but robust, by planning for cases that should not normally arise, but might out of Murphy's law, and ensuring they do not affect the software's basic safety and simplicity.
It is sometimes useful, when handling exceptions in <code>rescue</code> clauses, to ascertain the exact nature of the exception that got the execution there. For this it is suffices to inherit from the Kernel Library class <code>EXCEPTIONS</code>, which provides queries such as <code>exception</code>, giving the code for the last exception, and symbolic names ( [[10 Other Mechanisms#Constant_and_unique_attributes|"Constant and unique attributes"]] ) for all such codes, such as <code>No_more_memory</code>. You can then process different exceptions differently by testing <code>exception</code> against various possibilities. The method strongly suggests, however, that exception handling code should remain simple; a complicated algorithm in a <code>rescue</code> clause is usually a sign that the mechanism is being misused. Class <code>EXCEPTIONS</code> also provides various facilities for fine-tuning the exception facilities, such as a procedure <code>raise</code> that will explicitly trigger a "developer exception" with a code than can then be detected and processed. Exception handling helps produce Eiffel software that is not just correct but robust, by planning for cases that should not normally arise, but might out of Murphy's law, and ensuring they do not affect the software's basic safety and simplicity.
==Other applications of Design by Contract&#153;==
The Design by Contract&#153; ideas pervade the Eiffel method. In addition to the applications just mentioned, they have two particularly important consequences: <br/>
* They make it possible to use Eiffel for analysis and design. At a high level of abstraction, it is necessary to be precise too. With the exception of BON, object-oriented analysis and design methods tend to favor abstraction over precision. Thanks to assertions, it is possible to express precise properties of a system ("At what speed should the alarm start sounding?") without making any commitment to implementation. The discussion of deferred classes ( [[9 Inheritance|"Applications of deferred classes", page 60]] ) will show how to write a purely descriptive, non-software model in Eiffel, using contracts to describe the essential properties of a system without any computer or software aspect.
* Assertions also serve to control the power of inheritance-related mechanisms -- redeclaration, polymorphism, dynamic binding -- and channel them to correct uses by assigning the proper semantic limits. See [[9 Inheritance|"Inheritance and contracts", page 66]] .
* They make it possible to use Eiffel for analysis and design. At a high level of abstraction, it is necessary to be precise too. With the exception of BON, object-oriented analysis and design methods tend to favor abstraction over precision. Thanks to assertions, it is possible to express precise properties of a system ("At what speed should the alarm start sounding?") without making any commitment to implementation. The discussion of deferred classes ( [[9 Inheritance#Applications_of_deferred_classes|"Applications of deferred classes"]] ) will show how to write a purely descriptive, non-software model in Eiffel, using contracts to describe the essential properties of a system without any computer or software aspect.
* Assertions also serve to control the power of inheritance-related mechanisms -- redeclaration, polymorphism, dynamic binding -- and channel them to correct uses by assigning the proper semantic limits. See [[9 Inheritance#Inheritance_and_contracts|"Inheritance and contracts"]] .

View File

@@ -8,9 +8,9 @@ We now examine a few important mechanisms that complement the preceding picture:
The Eiffel's method obsession with extendibility, reusability and maintainability yields, as has been seen, modular and decentralized architectures, where inter-module coupling is limited to the strictly necessary, interfaces are clearly delimited, and all the temptations to introduce obscure dependencies, in particular global variables, have been removed. There is a need, however, to let various components of a system access common objects, without requiring their routines to pass these objects around as arguments (which would only be slightly better than global variables). For example various classes may need to perform output to a common "console window", represented by a shared object.
Eiffel addresses this need through an original mechanism that also takes care of another important issue, poorly addressed by many design and programming approaches: initialization. The idea is simple: if instead of <code> do </code> the implementation of an effective routine starts with the keyword <code> once </code>, it will only be executed the first time the routine is called during a system execution (or, in a multi-threaded environment, the first time in each thread), regardless of what the caller was. Subsequent calls from the same caller or others will have no effect; if the routine is a function, it will always return the result computed by the first call -- object if an expanded type, reference otherwise.
Eiffel addresses this need through an original mechanism that also takes care of another important issue, poorly addressed by many design and programming approaches: initialization. The idea is simple: if instead of <code>do</code> the implementation of an effective routine starts with the keyword <code>once</code>, it will only be executed the first time the routine is called during a system execution (or, in a multi-threaded environment, the first time in each thread), regardless of what the caller was. Subsequent calls from the same caller or others will have no effect; if the routine is a function, it will always return the result computed by the first call -- object if an expanded type, reference otherwise.
In the case of procedures, this provides a convenient initialization mechanism. A delicate problem in the absence of a <code> once </code> mechanism is how to provide the users of a library with a set of routines which they can call in any order, but which all need, to function properly, the guarantee that some context had been properly set up. Asking the library clients to precede the first call with a call to an initialization procedure <code> setup </code> is not only user-unfriendly but silly: in a well-engineered system we will want to check proper set-up in every of the routines, and report an error if necessary; but then if we were able to detect improper set-up we might as well shut up and set up ourselves (by calling <code> setup </code>). This is not easy, however, since the object on which we call <code> setup </code> must itself be properly initialized, so we are only pushing the problem further. Making <code> setup </code> a <code> once </code> procedure solves it: we can simply include a call
In the case of procedures, this provides a convenient initialization mechanism. A delicate problem in the absence of a <code>once</code> mechanism is how to provide the users of a library with a set of routines which they can call in any order, but which all need, to function properly, the guarantee that some context had been properly set up. Asking the library clients to precede the first call with a call to an initialization procedure <code>setup</code> is not only user-unfriendly but silly: in a well-engineered system we will want to check proper set-up in every of the routines, and report an error if necessary; but then if we were able to detect improper set-up we might as well shut up and set up ourselves (by calling <code>setup</code>). This is not easy, however, since the object on which we call <code>setup</code> must itself be properly initialized, so we are only pushing the problem further. Making <code>setup</code> a <code>once</code> procedure solves it: we can simply include a call
<code>
setup
</code>
@@ -26,11 +26,11 @@ console: WINDOW is
end
</code>
Whatever client first calls this function will create the appropriate window and return a reference to it. Subsequent calls, from anywhere in the system, will return that same reference. The simplest way to make this function available to a set of classes is to include it in a class <code> SHARED_STRUCTURES </code> which the classes needing a set of related shared objects will simply inherit.
Whatever client first calls this function will create the appropriate window and return a reference to it. Subsequent calls, from anywhere in the system, will return that same reference. The simplest way to make this function available to a set of classes is to include it in a class <code>SHARED_STRUCTURES</code> which the classes needing a set of related shared objects will simply inherit.
For the classes using it, <code> console </code>, although a function, looks very much as if it were an attribute -- only one referring to a shared object.
For the classes using it, <code>console</code>, although a function, looks very much as if it were an attribute -- only one referring to a shared object.
The "Hello World" system at the beginning of this discussion (section [[4 Hello World|4]] ) used an output instruction of the form <code> io </code>. <code> put_string ( Some string ) </code>. This is another example of the general scheme illustrated by <code> console </code>. Feature <code> io </code>, declared in <code> ANY </code> and hence usable by all classes, is a once function that returns an object of type <code> STANDARD_FILES </code> (another Kernel Library class) providing access to basic input and output features, one of which is procedure <code> put_string </code>. Because basic input and output must all work on the same files, <code> io </code> should clearly be a <code> once </code> function, shared by all classes that need these mechanisms.
The "Hello World" system at the beginning of this discussion (section [[4 Hello World|4]] ) used an output instruction of the form <code>io</code>. <code>put_string ( Some string )</code>. This is another example of the general scheme illustrated by <code>console</code>. Feature <code>io</code>, declared in <code>ANY</code> and hence usable by all classes, is a once function that returns an object of type <code>STANDARD_FILES</code> (another Kernel Library class) providing access to basic input and output features, one of which is procedure <code>put_string</code>. Because basic input and output must all work on the same files, <code>io</code> should clearly be a <code>once</code> function, shared by all classes that need these mechanisms.
==Constant and unique attributes==
@@ -43,34 +43,34 @@ Solar_system_planet_count: INTEGER is 9
These will have the same value for every instance and hence do not need to occupy any space in objects at execution time. (In other approaches similar needs would be addressed by symbolic constants, as in Pascal or Ada, or macros, as in C.)
What comes after the <code> is </code> is a manifest constant: a self-denoting value of the appropriate type. Manifest constants are available for integers, reals (also used for doubles), booleans ( <code> True </code> and <code> False </code>), characters (in single quotes, as <code> 'A' </code>, with special characters expressed using a percent sign as in <code> '%N' </code> for new line, <code> '%B' </code> for backspace and <code> '%U' </code> for null).
What comes after the <code>is</code> is a manifest constant: a self-denoting value of the appropriate type. Manifest constants are available for integers, reals (also used for doubles), booleans ( <code>True</code> and <code>False</code>), characters (in single quotes, as <code>'A'</code>, with special characters expressed using a percent sign as in <code>'%N'</code> for new line, <code>'%B'</code> for backspace and <code>'%U'</code> for null).
For integer constants, it is also possible to avoid specifying the values. A declaration of the form
<code>
a, b, c, ... n : INTEGER is unique
</code>
introduces <code> a </code>, <code> b </code>, <code> c </code>, ... <code> n </code> as constant integer attributes, whose value are assigned by the Eiffel compiler rather than explicitly by the programmer. The values are different for all <code> unique </code> attributes in a system; they are all positive, and, in a single declaration such as the above, guaranteed to be consecutive (so that you may use an invariant property of the form <code> code > a and code < n </code> to express that <code> code </code> should be one of the values). This mechanism replaces the "enumerated types" found in many languages, without suffering from the same problems. (Enumerated types have an ill-defined place in the type system; and it is not clear what operations are permitted.)
introduces <code>a</code>, <code>b</code>, <code>c</code>, ... <code>n</code> as constant integer attributes, whose value are assigned by the Eiffel compiler rather than explicitly by the programmer. The values are different for all <code>unique</code> attributes in a system; they are all positive, and, in a single declaration such as the above, guaranteed to be consecutive (so that you may use an invariant property of the form <code>code > a and code < n</code> to express that <code>code</code> should be one of the values). This mechanism replaces the "enumerated types" found in many languages, without suffering from the same problems. (Enumerated types have an ill-defined place in the type system; and it is not clear what operations are permitted.)
You may use Unique values in conjunction with the <code> inspect </code> multi-branch instruction studied in the next section. They are only appropriate for codes that can take on a fixed number of well-defined values -- not as a way to program operations with many variants, a need better addressed by the object-oriented technique studied earlier and relying on inheritance, polymorphism, redeclaration and dynamic binding.
You may use Unique values in conjunction with the <code>inspect</code> multi-branch instruction studied in the next section. They are only appropriate for codes that can take on a fixed number of well-defined values -- not as a way to program operations with many variants, a need better addressed by the object-oriented technique studied earlier and relying on inheritance, polymorphism, redeclaration and dynamic binding.
Manifest constants are also available for strings, using double quotes as in
<code>
User_friendly_error_message: STRING is "Go get a life !"
</code>
with special characters again using the <code> % </code> codes. It is also possible to declare manifest arrays using double angle brackets:
with special characters again using the <code>%</code> codes. It is also possible to declare manifest arrays using double angle brackets:
<code>
<<1, 2, 3, 5, 7, 11, 13, 17, 19>>
</code>
which is an expression of type <code> ARRAY [INTEGER] </code>. Manifest arrays and strings are not atomic, but denote instances of the Kernel Library classes <code> STRING </code> and <code> ARRAY </code>, as can be produced by once functions.
which is an expression of type <code>ARRAY [INTEGER]</code>. Manifest arrays and strings are not atomic, but denote instances of the Kernel Library classes <code>STRING</code> and <code>ARRAY</code>, as can be produced by once functions.
==Instructions==
Eiffel has a remarkably small set of instructions. The basic computational instructions have been seen: creation, assignment, assignment attempt, procedure call, retry. They are complemented by control structures: conditional, multi-branch, loop, as well as debug and check.
A conditional instruction has the form <code> if </code> ... <code> then </code> ... <code> elseif </code> ... <code> then </code> ... <code> else </code> ... <code> end </code>. The <code> elseif </code> ... <code> then </code> ... part (of which there may be more than one) and the <code> else </code> ... part are optional. After <code> if </code> and <code> elseif </code> comes a boolean expression; after <code> then </code>, <code> elseif </code> and <code> else </code> come zero or more instructions.
A conditional instruction has the form <code>if</code> ... <code>then</code> ... <code>elseif</code> ... <code>then</code> ... <code>else</code> ... <code>end</code>. The <code>elseif</code> ... <code>then</code> ... part (of which there may be more than one) and the <code>else</code> ... part are optional. After <code>if</code> and <code>elseif</code> comes a boolean expression; after <code>then</code>, <code>elseif</code> and <code>else</code> come zero or more instructions.
A multi-branch instruction has the form
<code>
@@ -86,11 +86,11 @@ else
end
</code>
where the <code> else </code> ''inst0'' part is optional, <code> exp </code> is a character or integer expression, ''v1'', ''v1'', ... are constant values of the same type as <code> exp </code>, all different, and ''inst0'', ''inst1'', ''inst2'', ... are sequences of zero or more instructions. In the integer case, it is often convenient to use <code> unique </code> values ( [[10 Other Mechanisms|"Constant and unique attributes", page 83]] ) for the ''vi''
where the <code>else</code> ''inst0'' part is optional, <code>exp</code> is a character or integer expression, ''v1'', ''v1'', ... are constant values of the same type as <code>exp</code>, all different, and ''inst0'', ''inst1'', ''inst2'', ... are sequences of zero or more instructions. In the integer case, it is often convenient to use <code>unique</code> values ( [[10 Other Mechanisms|"Constant and unique attributes", page 83]] ) for the ''vi''
The effect of such a multi-branch instruction, if the value of <code> exp </code> is one of the ''vi'', is to execute the corresponding ''insti''. If none of the ''vi'' matches, the instruction executes ''inst0'', unless there is no <code> else </code> part, in which case it triggers an exception.
The effect of such a multi-branch instruction, if the value of <code>exp</code> is one of the ''vi'', is to execute the corresponding ''insti''. If none of the ''vi'' matches, the instruction executes ''inst0'', unless there is no <code>else</code> part, in which case it triggers an exception.
{{note|Raising an exception is the proper behavior, since the absence of an <code> else </code> indicates that the author asserts that one of the values will match. If you want an instruction that does nothing in this case, rather than cause an exception, use an <code> else </code> part with an empty ''inst0''. In contrast, <code> if c then </code> ''inst'' <code> end </code> with no <code> else </code> part does nothing in the absence of an <code> else </code> part, since in this case there is no implied claim that <code> c </code> must hold. }}
{{note|Raising an exception is the proper behavior, since the absence of an <code>else</code> indicates that the author asserts that one of the values will match. If you want an instruction that does nothing in this case, rather than cause an exception, use an <code>else</code> part with an empty ''inst0''. In contrast, <code>if c then</code> ''inst'' <code>end</code> with no <code>else</code> part does nothing in the absence of an <code>else</code> part, since in this case there is no implied claim that <code>c</code> must hold. }}
The loop construct has the form
<code>
@@ -107,17 +107,17 @@ loop
end
</code>
where the <code> invariant </code> ''inv'' and <code> variant </code> ''var'' parts are optional, the others required. ''initialization'' and ''body'' are sequences of zero or more instructions; ''exit'' and ''inv'' are boolean expressions (more precisely, ''inv'' is an assertion); ''var'' is an integer expression.
where the <code>invariant</code> ''inv'' and <code>variant</code> ''var'' parts are optional, the others required. ''initialization'' and ''body'' are sequences of zero or more instructions; ''exit'' and ''inv'' are boolean expressions (more precisely, ''inv'' is an assertion); ''var'' is an integer expression.
The effect is to execute ''initialization'', then, zero or more times until ''exit'' is satisfied, to execute ''body''. (If after ''initialization'' the value of ''exit'' is already true, ''body'' will not be executed at all.) Note that the syntax of loops always includes an initialization, as most loops require some preparation. If not, just leave ''initialization''> empty, while including the <code> from </code> since it is a required component.
The effect is to execute ''initialization'', then, zero or more times until ''exit'' is satisfied, to execute ''body''. (If after ''initialization'' the value of ''exit'' is already true, ''body'' will not be executed at all.) Note that the syntax of loops always includes an initialization, as most loops require some preparation. If not, just leave ''initialization''> empty, while including the <code>from</code> since it is a required component.
The assertion ''inv'', if present, expresses a '''loop invariant''' (not to be confused with class invariants). For the loop to be correct, ''initialization'' must ensure ''inv'', and then every iteration of ''body'' executed when ''exit'' is false must preserve the invariant; so the effect of the loop is to yield a state in which both ''inv'' and ''exit'' are true. The loop must terminate after a finite number of iterations, of course; this can be guaranteed by using a '''loop variant''' ''var''. It must be an integer expression whose value is non-negative after execution of ''initialization'', and decreased by at least one, while remain non-negative, by any execution of ''body'' when ''exit'' is false; since a non-negative integer cannot be decreased forever, this ensures termination. The assertion monitoring mode, if turned on at the highest level, will check these properties of the invariant and variant after initialization and after each loop iteration, triggering an exception if the invariant does not hold or the variant is negative or does not decrease.
An occasionally useful instruction is <code> debug </code> <code> ( </code>''Debug_key'', ... <code> ) </code> ''instructions'' <code> end </code> where ''instructions'' is a sequence of zero or more instructions and the part in parentheses is optional, containing if present one or more strings, called debug keys. The EiffelStudio compiler lets you specify the corresponding <code> debug </code> compilation option: <code> yes </code>, <code> no </code>, or an explicit debug key. The ''instructions''will be executed if and only if the corresponding option is on. The obvious use is for instructions that should be part of the system but executed only in some circumstances, for example to provide extra debugging information.
An occasionally useful instruction is <code>debug</code> <code>(</code>''Debug_key'', ... <code>)</code> ''instructions'' <code>end</code> where ''instructions'' is a sequence of zero or more instructions and the part in parentheses is optional, containing if present one or more strings, called debug keys. The EiffelStudio compiler lets you specify the corresponding <code>debug</code> compilation option: <code>yes</code>, <code>no</code>, or an explicit debug key. The ''instructions''will be executed if and only if the corresponding option is on. The obvious use is for instructions that should be part of the system but executed only in some circumstances, for example to provide extra debugging information.
The final instruction is connected with Design by Contract&#153;. The instruction <code> check </code> ''Assertion'' <code> end </code>, where ''Assertion'' is a sequence of zero or more assertions, will have no effect unless assertion monitoring is turned on at the <code> Check </code> level or higher. If so it will evaluate all the assertions listed, having no further effect if they are all satisfied; if any one of them does not hold, the instruction will trigger an exception.
The final instruction is connected with Design by Contract&#153;. The instruction <code>check</code> ''Assertion'' <code>end</code>, where ''Assertion'' is a sequence of zero or more assertions, will have no effect unless assertion monitoring is turned on at the <code>Check</code> level or higher. If so it will evaluate all the assertions listed, having no further effect if they are all satisfied; if any one of them does not hold, the instruction will trigger an exception.
This instruction serves to state properties that are expected to be satisfied at some stages of the computation -- other than the specific stages, such as routine entry and exit, already covered by the other assertion mechanisms such as preconditions, postconditions and invariants. A recommended use of <code> check </code> involves calling a routine with a precondition, where the call, for good reason, does not explicitly test for the precondition. Consider a routine of the form
This instruction serves to state properties that are expected to be satisfied at some stages of the computation -- other than the specific stages, such as routine entry and exit, already covered by the other assertion mechanisms such as preconditions, postconditions and invariants. A recommended use of <code>check</code> involves calling a routine with a precondition, where the call, for good reason, does not explicitly test for the precondition. Consider a routine of the form
<code>
r (ref: SOME_REFERENCE_TYPE) is
require
@@ -128,12 +128,12 @@ r (ref: SOME_REFERENCE_TYPE) is
end
</code>
Because of the call to <code> some_feature </code>, the routine will only work if its precondition is satisfied on entry. To guarantee this precondition, the caller may protect it by the corresponding test, as in
Because of the call to <code>some_feature</code>, the routine will only work if its precondition is satisfied on entry. To guarantee this precondition, the caller may protect it by the corresponding test, as in
<code>
if x /= Void then a.r (x) end
</code>
but this is not the only possible scheme; for example if an <code> create x </code> appears shortly before the call we know <code> x </code> is not void and do not need the protection. It is a good idea in such cases to use a <code> check </code> instruction to document this property, if only to make sure that a reader of the code will realize that the omission of an explicit test (justified or not) was not a mistake. This is particularly appropriate if the justification for not testing the precondition is less obvious. For example <code> x </code> could have been obtained, somewhere else in the algorithm, as <code> clone (y) </code> for some <code> y </code> that you know is not void. You should document this knowledge by writing the call as
but this is not the only possible scheme; for example if an <code>create x</code> appears shortly before the call we know <code>x</code> is not void and do not need the protection. It is a good idea in such cases to use a <code>check</code> instruction to document this property, if only to make sure that a reader of the code will realize that the omission of an explicit test (justified or not) was not a mistake. This is particularly appropriate if the justification for not testing the precondition is less obvious. For example <code>x</code> could have been obtained, somewhere else in the algorithm, as <code>clone (y)</code> for some <code>y</code> that you know is not void. You should document this knowledge by writing the call as
<code>
check
x_not_void: x /= Void end
@@ -143,7 +143,7 @@ end
a.r (x)
</code>
{{recommended|An extra indentation of the <code> check </code> part to separate it from the algorithm proper; and inclusion of a comment listing the rationale behind the developer's decision not to check explicitly for the precondition. }}
{{recommended|An extra indentation of the <code>check</code> part to separate it from the algorithm proper; and inclusion of a comment listing the rationale behind the developer's decision not to check explicitly for the precondition. }}
In production mode with assertion monitoring turned off, this instruction will have no effect. But it will be precious for a maintainer of the software who is trying to figure out what it does, and in the process to reconstruct the original developer's reasoning. (The maintainer might of course be the same person as the developer, six months later.) And if the rationale is wrong somewhere, turning assertion checking on will immediately uncover the bug.
@@ -153,7 +153,7 @@ One of the conditions for producing truly great reusable software is to recogniz
This raises the issue of backward compatibility: how to move forward with a better design, without compromising existing applications that used the previous version?
The notion of obsolete class and feature helps address this issue. By declaring a feature as <code> obsolete </code>, using the syntax
The notion of obsolete class and feature helps address this issue. By declaring a feature as <code>obsolete</code>, using the syntax
<code>
enter (i: INTEGER; x: G) is
obsolete
@@ -165,18 +165,18 @@ enter (i: INTEGER; x: G) is
end
</code>
you state that you are now advising against using it, and suggest a replacement through the message that follows the keyword <code> obsolete </code>, a mere string. The obsolete feature is still there, however; using it will cause no other harm than a warning message when someone compiles a system that includes a call to it. Indeed, you don't want to hold a gun to your client authors' forehead (''"Upgrade now or die !"''); but you do want to let them know that there is a new version and that they should upgrade at their leisure.
you state that you are now advising against using it, and suggest a replacement through the message that follows the keyword <code>obsolete</code>, a mere string. The obsolete feature is still there, however; using it will cause no other harm than a warning message when someone compiles a system that includes a call to it. Indeed, you don't want to hold a gun to your client authors' forehead (''"Upgrade now or die !"''); but you do want to let them know that there is a new version and that they should upgrade at their leisure.
Besides routines, you may also mark classes as obsolete.
The example above is a historical one, involving an early change of interface for the EiffelBase library class <code> ARRAY </code>; the change affected both the feature's name, with a new name ensuring better consistency with other classes, and the order of arguments, again for consistency. It shows the recommended style for using <code> obsolete </code>: <br/>
The example above is a historical one, involving an early change of interface for the EiffelBase library class <code>ARRAY</code>; the change affected both the feature's name, with a new name ensuring better consistency with other classes, and the order of arguments, again for consistency. It shows the recommended style for using <code>obsolete</code>: <br/>
* In the message following the keyword, explain the recommended replacement. This message will be part of the warning produced by the compiler for a system that includes the obsolete element.
* In the body of the routine, it is usually appropriate, as here, to replace the original implementation by a call to the new version. This may imply a small performance overhead, but simplifies maintenance and avoids errors.
It is good discipline not to let obsolete elements linger around for too long. The next major new release, after a suitable grace period, should remove them.
The design flexibility afforded by the <code> obsolete </code> keyword is critical to ensure the harmonious long-term development of ambitious reusable software.
The design flexibility afforded by the <code>obsolete</code> keyword is critical to ensure the harmonious long-term development of ambitious reusable software.
==Creation variants==
@@ -186,12 +186,12 @@ create x.make (2000)
create x
</code>
the first one if the corresponding class has a <code> create </code> clause, the second one if not. In either form you may include a type name in braces, as in
the first one if the corresponding class has a <code>create</code> clause, the second one if not. In either form you may include a type name in braces, as in
<code>
create {SAVINGS_ACCOUNT} x.make (2000)
</code>
which is valid only if the type listed, here <code> SAVINGS_ACCOUNT </code>, conforms to the type of <code> x </code>, assumed here to be <code> ACCOUNT </code>. This avoids introducing a local entity, as in
which is valid only if the type listed, here <code>SAVINGS_ACCOUNT</code>, conforms to the type of <code>x</code>, assumed here to be <code>ACCOUNT</code>. This avoids introducing a local entity, as in
<code>
local
xs: SAVINGS_ACCOUNT
@@ -216,16 +216,16 @@ do
...
</code>
Unlike creation instructions, creation expressions must always list the type explicitly, <code> {ACCOUNT} </code> in the example. They are useful in the case shown: creating an object that only serves as an argument to be passed to a routine. If you need to retain access to the object through an entity, the instruction <code> create x </code> ... is the appropriate construct.
Unlike creation instructions, creation expressions must always list the type explicitly, <code>{ACCOUNT}</code> in the example. They are useful in the case shown: creating an object that only serves as an argument to be passed to a routine. If you need to retain access to the object through an entity, the instruction <code>create x</code> ... is the appropriate construct.
The creation mechanism gets an extra degree of flexibility through the notion of <code> default_create </code>. The simplest form of creation instruction, <code> create x </code> without an explicit creation procedure, is actually an abbreviation for <code> create x.default_create </code>, where <code> default_create </code> is a procedure defined in class <code> ANY </code> to do nothing. By redefining <code> default_create </code> in one of your classes, you can ensure that <code> create x </code> will take care of non-default initialization (and ensure the invariant if needed). When a class has no <code> create </code> clause, it's considered to have one that lists only <code> default_create </code>. If you want to allow <code> create x </code> as well as the use of some explicit creation procedures, simply list <code> default_create </code> along with these procedures in the <code> create </code> clause. To disallow creation altogether, include an empty <code> create </code> clause, although this technique is seldom needed since most non-creatable classes are deferred, and one can't instantiate a deferred class.
The creation mechanism gets an extra degree of flexibility through the notion of <code>default_create</code>. The simplest form of creation instruction, <code>create x</code> without an explicit creation procedure, is actually an abbreviation for <code>create x.default_create</code>, where <code>default_create</code> is a procedure defined in class <code>ANY</code> to do nothing. By redefining <code>default_create</code> in one of your classes, you can ensure that <code>create x</code> will take care of non-default initialization (and ensure the invariant if needed). When a class has no <code>create</code> clause, it's considered to have one that lists only <code>default_create</code>. If you want to allow <code>create x</code> as well as the use of some explicit creation procedures, simply list <code>default_create</code> along with these procedures in the <code>create</code> clause. To disallow creation altogether, include an empty <code>create</code> clause, although this technique is seldom needed since most non-creatable classes are deferred, and one can't instantiate a deferred class.
One final twist is the mechanism for creating instances of formal generic parameters. For <code> x </code> of type <code> G </code> in a class <code> C [G] </code>, it wouldn't be safe to allow <code> create x </code>, since <code> G </code> stands for many possible types, all of which may have their own creation procedures. To allow such creation instructions, we rely on constrained genericity. You may declare a class as
One final twist is the mechanism for creating instances of formal generic parameters. For <code>x</code> of type <code>G</code> in a class <code>C [G]</code>, it wouldn't be safe to allow <code>create x</code>, since <code>G</code> stands for many possible types, all of which may have their own creation procedures. To allow such creation instructions, we rely on constrained genericity. You may declare a class as
<code>
[G -> T create cp end]
</code>
to make <code> G </code> constrained by <code> T </code>, as we learned before, and specify that any actual generic parameter must have <code> cp </code> among its creation procedures. Then it's permitted to use <code> create x.cp </code>, with arguments if required by <code> cp </code>, since it is guaranteed to be safe. The mechanism is very general since you may use <code> ANY </code> for <code> T </code> and <code> default_create </code> for <code> cp </code>. The only requirement on <code> cp </code> is that it must be a procedure of <code> T </code>, not necessarily a creation procedure; this permits using the mechanism even if <code> T </code> is deferred, a common occurrence. It's only descendants of <code> T </code> that must make <code> cp </code> a creation procedure, by listing it in the <code> create </code> clause, if they want to serve as actual generic parameters for <code> C </code>.
to make <code>G</code> constrained by <code>T</code>, as we learned before, and specify that any actual generic parameter must have <code>cp</code> among its creation procedures. Then it's permitted to use <code>create x.cp</code>, with arguments if required by <code>cp</code>, since it is guaranteed to be safe. The mechanism is very general since you may use <code>ANY</code> for <code>T</code> and <code>default_create</code> for <code>cp</code>. The only requirement on <code>cp</code> is that it must be a procedure of <code>T</code>, not necessarily a creation procedure; this permits using the mechanism even if <code>T</code> is deferred, a common occurrence. It's only descendants of <code>T</code> that must make <code>cp</code> a creation procedure, by listing it in the <code>create</code> clause, if they want to serve as actual generic parameters for <code>C</code>.
==Tuple types==
@@ -234,24 +234,24 @@ The study of genericity described arrays. Another common kind of container objec
TUPLE [X, Y, Z]
</code>
denoting a tuple of least three elements, such that the type of the first conforms to <code> X </code>, the second to <code> Y </code>, and the third to <code> Z </code>.
denoting a tuple of least three elements, such that the type of the first conforms to <code>X</code>, the second to <code>Y</code>, and the third to <code>Z</code>.
You may list any number of types in brackets, including none at all: <code> TUPLE </code>, with no types in brackets, denotes tuples of arbitrary length.
You may list any number of types in brackets, including none at all: <code>TUPLE</code>, with no types in brackets, denotes tuples of arbitrary length.
{{info|The syntax, with brackets, is intentionally reminiscent of generic classes, but <code> TUPLE </code> is a reserved word, not the name of a class; making it a class would not work since a generic class has a fixed number of generic parameters. You may indeed use <code> TUPLE </code> to obtain the effect of a generic class with a variable number of parameters. }}
{{info|The syntax, with brackets, is intentionally reminiscent of generic classes, but <code>TUPLE</code> is a reserved word, not the name of a class; making it a class would not work since a generic class has a fixed number of generic parameters. You may indeed use <code>TUPLE</code> to obtain the effect of a generic class with a variable number of parameters. }}
To write the tuples themselves -- the sequences of elements, instances of a tuple type -- you will also use square brackets; for example
<code>
[x1, y1, z1]
</code>
with <code> x1 </code> of type <code> X </code> and so on is a tuple of type <code> TUPLE [X, Y, Z] </code>.
with <code>x1</code> of type <code>X</code> and so on is a tuple of type <code>TUPLE [X, Y, Z]</code>.
The definition of tuple types states that <code> TUPLE [X1 ... Xn] </code> denotes sequences of at least <code> n </code> elements, of which the first <code> n </code> have types respectively conforming to <code> X1, ..., Xn </code>. Such a sequence may have more than <code> n </code> elements.
The definition of tuple types states that <code>TUPLE [X1 ... Xn]</code> denotes sequences of at least <code>n</code> elements, of which the first <code>n</code> have types respectively conforming to <code>X1, ..., Xn</code>. Such a sequence may have more than <code>n</code> elements.
Features available on tuple types include <code> count: INTEGER </code>, yielding the number of elements in a tuple, <code> item (i: INTEGER): ANY </code> which returns the <code> i </code>-th element, and <code> put </code> which replaces an element.
Features available on tuple types include <code>count: INTEGER</code>, yielding the number of elements in a tuple, <code>item (i: INTEGER): ANY</code> which returns the <code>i</code>-th element, and <code>put</code> which replaces an element.
Tuples are appropriate when these are the only operations you need, that is to say, you are using sequences with no further structure or properties. Tuples give you "anonymous classes" with predefined features <code> count </code>, <code> item </code> and <code> put </code>. A typical example is a general-purpose output procedure that takes an arbitrary sequence of values, of arbitrary types, and prints them. It may simply take an argument of type <code> TUPLE </code>, so that clients can call it under the form
Tuples are appropriate when these are the only operations you need, that is to say, you are using sequences with no further structure or properties. Tuples give you "anonymous classes" with predefined features <code>count</code>, <code>item</code> and <code>put</code>. A typical example is a general-purpose output procedure that takes an arbitrary sequence of values, of arbitrary types, and prints them. It may simply take an argument of type <code>TUPLE</code>, so that clients can call it under the form
<code>
write ([ ''your_integer'' , ''your_real'', ''your_account''])