Author:halw

Date:2008-10-13T22:01:47.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@79 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
halw
2008-10-13 22:01:47 +00:00
parent b5409df103
commit b2f92d3e33
20 changed files with 136 additions and 91 deletions

View File

@@ -19,20 +19,22 @@ The term "entity" generalizes the more common notion of "variable". An entity de
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>
<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>
<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:
These feature calls use dot notation, of the form <code> target_name.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.
@@ -42,34 +44,35 @@ Routines are further divided into '''procedures''' (commands, which do not retur
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
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.add ( -3000 ) </code> would be invalid.
<code>
class ACCOUNT
feature
balance: INTEGER
owner: PERSON
minimum_balance: INTEGER is 1000
minimum_balance: INTEGER = 1000
open (who: PERSON) is
open (who: PERSON)
-- Assign the account to owner who.
do
owner := who
end
deposit (sum: INTEGER) is
deposit (sum: INTEGER)
-- Deposit sum into the account.
do
add (sum)
end
withdraw (sum: INTEGER) is
withdraw (sum: INTEGER)
-- Withdraw sum from the account.
do
add (-sum)
end
may_withdraw (sum: INTEGER): BOOLEAN is
may_withdraw (sum: INTEGER): BOOLEAN
-- Is there enough money to withdraw sum?
do
Result := (balance >= sum + minimum_balance)
@@ -77,7 +80,7 @@ feature
feature {NONE}
add (sum: INTEGER) is
add (sum: INTEGER)
-- Add sum to the balance
do
balance := balance + sum
@@ -86,19 +89,19 @@ feature {NONE}
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.
Let us examine the features in sequence. The <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>.
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> = 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".
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.open ("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.
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.plus (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

@@ -13,7 +13,8 @@ Eiffel encourages software developers to express formal properties of classes by
With appropriate assertions, the class <code> ACCOUNT </code> becomes:
<code>class ACCOUNT
<code>
class ACCOUNT
create
make
@@ -21,7 +22,7 @@ feature
... Attributes as before:
balance , minimum_balance , owner , open ...
deposit (sum: INTEGER) is
deposit (sum: INTEGER)
-- Deposit sum into the account.
require
sum >= 0
@@ -31,7 +32,7 @@ feature
balance = old balance + sum
end
withdraw (sum: INTEGER) is
withdraw (sum: INTEGER)
-- Withdraw sum from the account.
require
sum >= 0
@@ -48,7 +49,7 @@ feature {NONE}
add ...
make (initial: INTEGER) is
make (initial: INTEGER)
-- Initialize account with balance initial.
require
initial >= minimum_balance
@@ -67,16 +68,23 @@ The notation <code> old </code> <code> expression </code> is only valid in a rou
==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>
<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. }}
{{info|The underscore <code>_</code> in the integer constant ''5_500'' 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>
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 {NONE} </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.
@@ -104,14 +112,14 @@ feature
balance: INTEGER
...
deposit (sum: INTEGER) is
deposit (sum: INTEGER)
-- Deposit sum into the account.
require
sum >= 0
ensure
balance = old balance + sum
withdraw (sum: INTEGER) is
withdraw (sum: INTEGER)
-- Withdraw sum from the account.
require
sum >= 0

View File

@@ -19,7 +19,7 @@ Usually, only a few routines of a system will explicitly include a <code> rescue
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
attempt_transmission (message: STRING)
-- Try to transmit message, at most 50 times.
-- Set successful accordingly.
local

View File

@@ -8,6 +8,7 @@ An in-depth discussion of these principles fall beyond the scope of this introdu
{{info|Object-oriented design is the construction of software systems as structured collections of abstract data type implementations, or "classes". }}
The following points are worth noting in this definition:<br/>
* The emphasis is on structuring a system around the types of objects it manipulates (not the functions it performs on them) and on reusing whole data structures together with the associated operations (not isolated routines).
* Objects are described as instances of abstract data types -- that is to say, data structures known from an official interface rather than through their representation.

View File

@@ -8,9 +8,13 @@ Any type <code> T </code> is based on a class, which defines the operations that
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 "<".
In contrast, the value of an entity <code> acc </code> declared of type <code>expanded 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.