mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2026-08-08 11:41:12 +02:00
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:
@@ -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.
|
||||
|
||||
|
||||
+18
-10
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user