mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-08 15:52:26 +01:00
Author:halw
Date:2008-10-21T19:55:42.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@92 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
[[Property:title|Community]]
|
[[Property:title|Community]]
|
||||||
[[Property:weight|2]]
|
[[Property:weight|2]]
|
||||||
[[Property:uuid|75c75712-7c3e-2757-51b7-77b404471e2e]]
|
[[Property:uuid|75c75712-7c3e-2757-51b7-77b404471e2e]]
|
||||||
EiffelStudio community:
|
Eiffel is a community. Members of the Eiffel community can contribute to this documentation through this book.
|
||||||
|
|
||||||
|
|
||||||
:'''You can become a contributor!'''
|
:'''You can become a contributor!'''
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,45 +14,45 @@ In a number of applications, however, we may need objects that represent operati
|
|||||||
* Numerical computation, where we may define a routine that computes the integral of any applicable function on any applicable interval; to represent that function and pass its representation to the integration routine, we will use an agent.
|
* Numerical computation, where we may define a routine that computes the integral of any applicable function on any applicable interval; to represent that function and pass its representation to the integration routine, we will use an agent.
|
||||||
|
|
||||||
|
|
||||||
Operations in Eiffel are expressed as routines, and indeed every agent will have an associated routine. Remember, however, that the fundamental distinction between objects and operations remains: an agent is an object, and it is not a routine; it represents a routine. As further evidence that this is a proper data abstraction, note that the procedure <code> call </code>, available on all agents to call the associated routine, is only one of the features of agents. Other features may denote properties such as the class to which the routine belongs, its precondition and postcondition, the result of the last call for a function, the number of arguments.
|
Operations in Eiffel are expressed as routines, and indeed every agent will have an associated routine. Remember, however, that the fundamental distinction between objects and operations remains: an agent is an object, and it is not a routine; it represents a routine. As further evidence that this is a proper data abstraction, note that the procedure <code>call</code>, available on all agents to call the associated routine, is only one of the features of agents. Other features may denote properties such as the class to which the routine belongs, its precondition and postcondition, the result of the last call for a function, the number of arguments.
|
||||||
|
|
||||||
==Building an agent==
|
==Building an agent==
|
||||||
|
|
||||||
In the simplest form, also one of the most common, you obtain an agent just by writing
|
In the simplest form, also one of the most common, you obtain an agent just by writing
|
||||||
<code>
|
<code>
|
||||||
agent r
|
agent r
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
where <code> r </code> is the name of a routine of the enclosing class. This is an expression, which you may assign to a writable entity, or pass as argument to a routine. Here for example is how you will specify event handling in the style of the EiffelVision 2 GUI library:
|
where <code>r</code> is the name of a routine of the enclosing class. This is an expression, which you may assign to a writable entity, or pass as argument to a routine. Here for example is how you will specify event handling in the style of the EiffelVision 2 GUI library:
|
||||||
<code>
|
<code>
|
||||||
your_icon.click_actions.extend (agent your_routine)
|
your_icon.click_actions.extend (agent your_routine)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
This adds to the end of <code> my_icon.click_actions </code> -- the list of agents associated with the "click" event for <code> my_icon </code>, denoting an icon in the application's user interface -- an agent representing <code> your_routine </code>. Then when a user clicks on the associated icon at execution, the EiffelVision 2 mechanisms will call the procedure <code> call </code> on every agent of the list, which for this agent will execute <code> your_routine </code>. This is a simple way to associate elements of your application, more precisely its "business model" (the processing that you have defined, directly connected to the application's business domain), with elements of its GUI.
|
This adds to the end of <code>my_icon.click_actions</code> -- the list of agents associated with the "click" event for <code>my_icon</code>, denoting an icon in the application's user interface -- an agent representing <code>your_routine</code>. Then when a user clicks on the associated icon at execution, the EiffelVision 2 mechanisms will call the procedure <code>call</code> on every agent of the list, which for this agent will execute <code>your_routine</code>. This is a simple way to associate elements of your application, more precisely its "business model" (the processing that you have defined, directly connected to the application's business domain), with elements of its GUI.
|
||||||
|
|
||||||
Similarly although in a completely different area, you may request the integration of a function <code> your_function </code> over the interval <code> 0..1 </code> through a call such as
|
Similarly although in a completely different area, you may request the integration of a function <code>your_function</code> over the interval <code>0..1</code> through a call such as
|
||||||
<code>
|
<code>
|
||||||
your_integrator.integral (agent your_function, 0, 1)
|
your_integrator.integral (agent your_function, 0, 1)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
In the third example area cited above, you may call an iterator of EiffelBase through
|
In the third example area cited above, you may call an iterator of EiffelBase through
|
||||||
<code>
|
<code>
|
||||||
your_list.do_all (agent your_proc)
|
your_list.do_all (agent your_proc)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
with <code> your_list </code> of a type such as <code> LIST [YOUR_TYPE] </code>. This will apply <code> your_proc </code> to every element of the list in turn.
|
with <code>your_list</code> of a type such as <code>LIST [YOUR_TYPE]</code>. This will apply <code>your_proc</code> to every element of the list in turn.
|
||||||
|
|
||||||
The agent mechanism is type-checked like the rest of Eiffel; so the last example is valid if and only if <code> your_proc </code> is a procedure with one argument of type <code> YOUR_TYPE </code>.
|
The agent mechanism is type-checked like the rest of Eiffel; so the last example is valid if and only if <code>your_proc</code> is a procedure with one argument of type <code>YOUR_TYPE</code>.
|
||||||
|
|
||||||
==Operations on agents==
|
==Operations on agents==
|
||||||
|
|
||||||
An agent <code> agent </code> <code> r </code> built from a procedure <code> r </code> is of type <code> PROCEDURE [T, ARGS] </code> where <code> T </code> represents the class to which <code> r </code> belongs and <code> ARGS </code> the type of its arguments. If <code> r </code> is a function of result type <code> RES </code>, the type is <code> FUNCTION [T, ARGS, RES] </code>. Classes <code> PROCEDURE </code> and <code> FUNCTION </code> are from the Kernel Library of EiffelBase, both inheriting from <code> ROUTINE [T, ARGS] </code>.
|
An agent <code>agent</code> <code>r</code> built from a procedure <code>r</code> is of type <code>PROCEDURE [T, ARGS]</code> where <code>T</code> represents the class to which <code>r</code> belongs and <code>ARGS</code> the type of its arguments. If <code>r</code> is a function of result type <code>RES</code>, the type is <code>FUNCTION [T, ARGS, RES]</code>. Classes <code>PROCEDURE</code> and <code>FUNCTION</code> are from the Kernel Library of EiffelBase, both inheriting from <code>ROUTINE [T, ARGS]</code>.
|
||||||
|
|
||||||
Among the features of <code> ROUTINE </code> and its descendants the most important are <code> call </code>, already noted, which calls the associated routine, and <code> item </code>, appearing only in <code> FUNCTION </code> and yielding the result of the associated function, which it obtains by calling <code> call </code>.
|
Among the features of <code>ROUTINE</code> and its descendants the most important are <code>call</code>, already noted, which calls the associated routine, and <code>item</code>, appearing only in <code>FUNCTION</code> and yielding the result of the associated function, which it obtains by calling <code>call</code>.
|
||||||
|
|
||||||
As an example of using these mechanisms, here is how the function <code> integral </code> could look like in our <code> INTEGRATOR </code> example class. The details of the integration algorithm (straight forward, and making no claims to numerical sophistication) do not matter, but you see, in the highlighted line, the place were we evaluate the mathematical function associated with <code> f </code>, by calling <code> item </code> on <code> f </code>:
|
As an example of using these mechanisms, here is how the function <code>integral</code> could look like in our <code>INTEGRATOR</code> example class. The details of the integration algorithm (straight forward, and making no claims to numerical sophistication) do not matter, but you see, in the highlighted line, the place were we evaluate the mathematical function associated with <code>f</code>, by calling <code>item</code> on <code>f</code>:
|
||||||
<code>
|
<code>
|
||||||
integral (f: FUNCTION [ANY, TUPLE [REAL], REAL]; low, high: REAL): REAL is
|
integral (f: FUNCTION [ANY, TUPLE [REAL], REAL]; low, high: REAL): REAL
|
||||||
-- Integral of `f' over the interval [`low', `high']
|
-- Integral of `f' over the interval [`low', `high']
|
||||||
require
|
require
|
||||||
meaningful_interval: low <= high
|
meaningful_interval: low <= high
|
||||||
@@ -75,120 +75,120 @@ integral (f: FUNCTION [ANY, TUPLE [REAL], REAL]; low, high: REAL): REAL is
|
|||||||
end
|
end
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
Function <code> integral </code> takes three arguments: the agent <code> f </code> representing the function to be integrated, and the two interval bounds. When we need to evaluate that function for the value <code> x </code>, in the line
|
Function <code>integral</code> takes three arguments: the agent <code>f</code> representing the function to be integrated, and the two interval bounds. When we need to evaluate that function for the value <code>x</code>, in the line
|
||||||
<code>
|
<code>
|
||||||
Result := Result + step * f.item ([x])
|
Result := Result + step * f.item ([x])
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
we don't directly pass <code> x </code> to <code> item </code>; instead, we pass a one-element tuple <code> [x] </code>, using the syntax for manifest tuples introduced in [[10 Other Mechanisms|"Tuple types", page 90]] . You will always use tuples for the argument to <code> call </code> and <code> item </code>, because these features must be applicable to any routine, and so cannot rely on a fixed number of arguments. Instead they take a single tuple intended to contain all the arguments. This property is reflected in the type of the second actual generic parameter to <code> f </code>, corresponding to <code> ARGS </code> (the formal generic parameter of <code> FUNCTION </code>): here it's <code> TUPLE [REAL] </code> to require an argument such as <code> [ x] </code>, where <code> x </code> is of type <code> REAL </code>.
|
we don't directly pass <code>x</code> to <code>item</code>; instead, we pass a one-element tuple <code>[x]</code>, using the syntax for manifest tuples introduced in [[10 Other Mechanisms#Tuple_types|"Tuple types"]] . You will always use tuples for the argument to <code>call</code> and <code>item</code>, because these features must be applicable to any routine, and so cannot rely on a fixed number of arguments. Instead they take a single tuple intended to contain all the arguments. This property is reflected in the type of the second actual generic parameter to <code>f</code>, corresponding to <code>ARGS</code> (the formal generic parameter of <code>FUNCTION</code>): here it's <code>TUPLE [REAL]</code> to require an argument such as <code>[ x]</code>, where <code>x</code> is of type <code>REAL</code>.
|
||||||
|
|
||||||
Similarly, consider the agent that the call seen above:
|
Similarly, consider the agent that the call seen above:
|
||||||
<code>
|
<code>
|
||||||
your_icon.click_actions.extend (agent your_routine)
|
your_icon.click_actions.extend (agent your_routine)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
added to an EiffelVision list. When the EiffelVision mechanism detects a mouse click event, it will apply to each element <code> item </code> of the list of agents, <code> your_icon.click_actions </code>, an instruction such as
|
added to an EiffelVision list. When the EiffelVision mechanism detects a mouse click event, it will apply to each element <code>item</code> of the list of agents, <code>your_icon.click_actions</code>, an instruction such as
|
||||||
<code>
|
<code>
|
||||||
item.call ([x, y])
|
item.call ([x, y])
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
where <code> x </code> and <code> y </code> are the coordinates of the mouse clicking position. If <code> item </code> denotes the list element <code> agent </code> your_routine, inserted by the above call to <code> extend </code>, the effect will be the same as that of calling
|
where <code>x</code> and <code>y</code> are the coordinates of the mouse clicking position. If <code>item</code> denotes the list element <code>agent</code> your_routine, inserted by the above call to <code>extend</code>, the effect will be the same as that of calling
|
||||||
<code>
|
<code>
|
||||||
your_routine (x, y)
|
your_routine (x, y)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
assuming that <code> your_routine </code> indeed takes arguments of the appropriate type, here <code> INTEGER </code> representing a coordinate in pixels. (Otherwise type checking would have rejected the call to <code> extend </code>.)
|
assuming that <code>your_routine</code> indeed takes arguments of the appropriate type, here <code>INTEGER</code> representing a coordinate in pixels. (Otherwise type checking would have rejected the call to <code>extend</code>.)
|
||||||
|
|
||||||
==Open and closed arguments==
|
==Open and closed arguments==
|
||||||
|
|
||||||
In the examples so far, execution of the agent's associated routine, through <code> item </code> or <code> call </code>, passed exactly the arguments that a direct call to the routine would expect. You can have more flexibility. In particular, you may build an agent from a routine with more arguments than expected in the final call, and you may set the values of some arguments at the time you define the agent.
|
In the examples so far, execution of the agent's associated routine, through <code>item</code> or <code>call</code>, passed exactly the arguments that a direct call to the routine would expect. You can have more flexibility. In particular, you may build an agent from a routine with more arguments than expected in the final call, and you may set the values of some arguments at the time you define the agent.
|
||||||
|
|
||||||
Assume for example that a cartographical application lets a user record the location of a city by clicking on the corresponding position on the map. The application may do this through a procedure
|
Assume for example that a cartographical application lets a user record the location of a city by clicking on the corresponding position on the map. The application may do this through a procedure
|
||||||
<code>
|
<code>
|
||||||
record_city (cn: STRING; pop: INTEGER; x, y: INTEGER)
|
record_city (cn: STRING; pop: INTEGER; x, y: INTEGER)
|
||||||
-- Record that the city of name `cn' is at coordinates
|
-- Record that the city of name `cn' is at coordinates
|
||||||
-- `x' and `y' with population `pop'.
|
-- `x' and `y' with population `pop'.
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
Then you can associate it with the GUI through a call such as
|
Then you can associate it with the GUI through a call such as
|
||||||
<code>
|
<code>
|
||||||
map.click_actions.extend (agent record_city (name, population, ?, ?))
|
map.click_actions.extend (agent record_city (name, population, ?, ?))
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
assuming that the information on the <code> name </code> and the <code> population </code> has already been determined. What the agent denotes is the same as <code> agent </code> <code> your_routine </code> as given before, where <code> your_routine </code> would be a fictitious two-argument routine obtained from <code> record_city </code> -- a four-argument routine -- by setting the first two arguments once and for all to the values given, <code> name </code> and <code> population </code>.
|
assuming that the information on the <code>name</code> and the <code>population</code> has already been determined. What the agent denotes is the same as <code>agent</code> <code>your_routine</code> as given before, where <code>your_routine</code> would be a fictitious two-argument routine obtained from <code>record_city</code> -- a four-argument routine -- by setting the first two arguments once and for all to the values given, <code>name</code> and <code>population</code>.
|
||||||
|
|
||||||
In the agent <code> agent record_city (name, population, ?, ?) </code>, we say that these first two arguments, with their set values, are '''closed'''; the last two are '''open'''. The question mark syntax introduced by this example may only appear in agent expressions; it denotes open arguments. This means, by the way, that you may view the basic form used in the preceding examples, <code> agent your_routine </code>, as an abbreviation -- assuming your_routine has two arguments -- for <code> agent your_routine (?, ?) </code>. It is indeed permitted, to define an agent with all arguments open, to omit the argument list altogether; no ambiguity may result.
|
In the agent <code>agent record_city (name, population, ?, ?)</code>, we say that these first two arguments, with their set values, are '''closed'''; the last two are '''open'''. The question mark syntax introduced by this example may only appear in agent expressions; it denotes open arguments. This means, by the way, that you may view the basic form used in the preceding examples, <code>agent your_routine</code>, as an abbreviation -- assuming your_routine has two arguments -- for <code>agent your_routine (?, ?)</code>. It is indeed permitted, to define an agent with all arguments open, to omit the argument list altogether; no ambiguity may result.
|
||||||
|
|
||||||
For type checking, <code> agent record_city (name, population, ?, ?) </code> and <code> agent ,your_routine </code> are acceptable in exactly the same situations, since both represent routines with two arguments. The type of both is
|
For type checking, <code>agent record_city (name, population, ?, ?)</code> and <code>agent your_routine (?, ?)</code> are acceptable in exactly the same situations, since both represent routines with two arguments. The type of both is
|
||||||
<code>
|
<code>
|
||||||
PROCEDURE [ANY, TUPLE [INTEGER, INTEGER]]
|
PROCEDURE [ANY, TUPLE [INTEGER, INTEGER]]
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
where the tuple type specifies the open operands.
|
where the tuple type specifies the open operands.
|
||||||
|
|
||||||
A completely closed agent, such as <code> agent your_routine (25, 32) </code> or <code> agent record_city (name, population, 25, 32) </code>, has the type <code> TUPLE </code>, with no parameters; you will call it with <code> call ([ ]) </code>, using an empty tuple as argument.
|
A completely closed agent, such as <code>agent your_routine (25, 32)</code> or <code>agent record_city (name, population, 25, 32)</code>, has the type <code>TUPLE</code>, with no parameters; you will call it with <code>call ([ ])</code>, using an empty tuple as argument.
|
||||||
|
|
||||||
The freedom to start from a routine with an arbitrary number of arguments, and choose which ones you want to close and which ones to leave open, provides a good part of the attraction of the agent mechanism. It means in particular that in GUI applications you can limit to the strict minimum the "glue" code (sometimes called the controller in the so-called MVC, Model-View Controller, scheme of GUI design) between the user interface and "business model" parts of a system. A routine such as <code> record_city </code> is a typical example of an element of the business model, uninfluenced -- as it should be -- by considerations of user interface design. Yet by passing it in the form of an agent with partially open and partially closed arguments, you may be able to use it directly in the GUI, as shown above, without any "controller" code.
|
The freedom to start from a routine with an arbitrary number of arguments, and choose which ones you want to close and which ones to leave open, provides a good part of the attraction of the agent mechanism. It means in particular that in GUI applications you can limit to the strict minimum the "glue" code (sometimes called the controller in the so-called MVC, Model-View Controller, scheme of GUI design) between the user interface and "business model" parts of a system. A routine such as <code>record_city</code> is a typical example of an element of the business model, uninfluenced -- as it should be -- by considerations of user interface design. Yet by passing it in the form of an agent with partially open and partially closed arguments, you may be able to use it directly in the GUI, as shown above, without any "controller" code.
|
||||||
|
|
||||||
As another example of the mechanism's versatility, we saw above an integral function that could integrate a function of one variable over an interval, as in
|
As another example of the mechanism's versatility, we saw above an integral function that could integrate a function of one variable over an interval, as in
|
||||||
<code>
|
<code>
|
||||||
your_integrator.integral (agent your_function (0, 1))
|
your_integrator.integral (agent your_function (0, 1))
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
Now assume that <code> function3 </code> takes three arguments. To integrate <code> function3 </code> with two arguments fixed, you don't need a new <code> integral </code> function; just use the same <code> integral </code> as before, judiciously selecting what to close and what to leave open:
|
Now assume that <code>function3</code> takes three arguments. To integrate <code>function3</code> with two arguments fixed, you don't need a new <code>integral</code> function; just use the same <code>integral</code> as before, judiciously selecting what to close and what to leave open:
|
||||||
<code>
|
<code>
|
||||||
your_integrator.integral (agent function3 (3.5, ?, 6.0), 0, 1)
|
your_integrator.integral (agent function3 (3.5, ?, 6.0), 0, 1)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
==Open targets==
|
==Open targets==
|
||||||
|
|
||||||
All the agent examples seen so far were based on routines of the enclosing class. This is not required. Feature calls, as you remember, were either unqualified, as in <code> f (x, y) </code>, or qualified, as in <code> a.g (x, y) </code>. Agents, too, have a qualified variant as in
|
All the agent examples seen so far were based on routines of the enclosing class. This is not required. Feature calls, as you remember, were either unqualified, as in <code>f (x, y)</code>, or qualified, as in <code>a.g (x, y)</code>. Agents, too, have a qualified variant as in
|
||||||
<code>
|
<code>
|
||||||
agent a.g
|
agent a.g
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
which is closed on its target <code> a </code> and open on the arguments. Variants such as <code> agent a.g (x, y) </code>, all closed, and <code> agent a.g (?, y) </code>, open on one argument, are all valid.
|
which is closed on its target <code>a</code> and open on the arguments. Variants such as <code>agent a.g (x, y)</code>, all closed, and <code>agent a.g (?, y)</code>, open on one argument, are all valid.
|
||||||
|
|
||||||
You may also want to make the target open. The question mark syntax could not work here, since it wouldn't tell us the class to which feature <code> g </code> belongs, known in the preceding examples from the type of <code> a </code>. As in creation expressions, we must list the type explicitly; the convention is the same: write the types in braces, as in
|
You may also want to make the target open. The question mark syntax could not work here, since it wouldn't tell us the class to which feature <code>g</code> belongs, known in the preceding examples from the type of <code>a</code>. As in creation expressions, we must list the type explicitly; the convention is the same: write the types in braces, as in
|
||||||
<code>
|
<code>
|
||||||
agent {SOME_TYPE}.g
|
agent {SOME_TYPE}.g
|
||||||
agent {SOME_TYPE}.g (?, ?)
|
agent {SOME_TYPE}.g (?, ?)
|
||||||
agent {SOME_TYPE}.g (?, y)
|
agent {SOME_TYPE}.g (?, y)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
The first two of these examples are open on the target and both operands; they mean the same. The third is closed on one argument, open on the other and on the target.
|
The first two of these examples are open on the target and both operands; they mean the same. The third is closed on one argument, open on the other and on the target.
|
||||||
|
|
||||||
These possibilities give even more flexibility to the mechanism because they mean that an operation that needs agents with certain arguments open doesn't care whether they come from an argument or an operand of the original routine. This is particularly useful for iterators and means that if you have two lists
|
These possibilities give even more flexibility to the mechanism because they mean that an operation that needs agents with certain arguments open doesn't care whether they come from an argument or an operand of the original routine. This is particularly useful for iterators and means that if you have two lists
|
||||||
<code>
|
<code>
|
||||||
your_account_list: LIST [ACCOUNT]
|
your_account_list: LIST [ACCOUNT]
|
||||||
your_integer_list: LIST [INTEGER]
|
your_integer_list: LIST [INTEGER]
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
you may write both
|
you may write both
|
||||||
<code>
|
<code>
|
||||||
your_account_list.do_all (agent deposit_one_grand)
|
your_account_list.do_all (agent deposit_one_grand)
|
||||||
your_integer_list.do_all (agent add_to_n)
|
your_integer_list.do_all (agent add_to_n)
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
even though the two procedures used in the agents have quite different forms. We are assuming here that the first one, in class <code> ACCOUNT </code>, is something like
|
even though the two procedures used in the agents have quite different forms. We are assuming here that the first one, in class <code>ACCOUNT</code>, is something like
|
||||||
<code>
|
<code>
|
||||||
deposit_one_grand is
|
deposit_one_grand
|
||||||
-- Add one thousand dollars to `balance' of account.
|
-- Add one thousand dollars to `balance' of account.
|
||||||
do
|
do
|
||||||
balance := balance + 1000
|
balance := balance + 1000
|
||||||
end
|
end
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
so that it doesn't take an argument: it is normally called on its target, as in <code> my_account.deposit_one_grand </code>. In contrast, the other routine has an argument:
|
so that it doesn't take an argument: it is normally called on its target, as in <code>my_account.deposit_one_grand</code>. In contrast, the other routine has an argument:
|
||||||
<code>
|
<code>
|
||||||
add_to_n (x: INTEGER) is
|
add_to_n (x: INTEGER)
|
||||||
-- Add `x' to the value of `total'.
|
-- Add `x' to the value of `total'.
|
||||||
do
|
do
|
||||||
total := total + x
|
total := total + x
|
||||||
end
|
end
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
where <code> total </code> is an integer attribute of the enclosing class. Without the versatility of playing with open and closed arguments for both the original arguments and target, you would have to write separate iteration mechanisms for these two cases. Here you can use a single iteration routine of <code> LIST </code> and similar classes of EiffelBase, <code> do_all </code>, for both purposes: <br/>
|
where <code>total</code> is an integer attribute of the enclosing class. Without the versatility of playing with open and closed arguments for both the original arguments and target, you would have to write separate iteration mechanisms for these two cases. Here you can use a single iteration routine of <code>LIST</code> and similar classes of EiffelBase, <code>do_all</code>, for both purposes: <br/>
|
||||||
* Depositing money on every account in a list of accounts.
|
* Depositing money on every account in a list of accounts.
|
||||||
* Adding all the integers in a list of integers.
|
* Adding all the integers in a list of integers.
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ The example assumed <code>x</code> declared of type <code>ACCOUNT</code> (or <co
|
|||||||
|
|
||||||
The third case, local entities, arises when a routine needs some auxiliary values for its computation. Here is an example of the syntax:
|
The third case, local entities, arises when a routine needs some auxiliary values for its computation. Here is an example of the syntax:
|
||||||
<code>
|
<code>
|
||||||
deposit (sum: INTEGER)
|
deposit (sum: INTEGER)
|
||||||
-- Add sum to account.
|
-- Add sum to account.
|
||||||
local
|
local
|
||||||
new: AMOUNT
|
new: AMOUNT
|
||||||
@@ -231,7 +231,7 @@ This example is a variant of <code> deposit </code> for which we assume that the
|
|||||||
|
|
||||||
The last case of entity, <code>Result</code>, serves to denote, within the body of a function, the final result to be returned by that function. This was illustrated by the function <code>deposit_count</code>, which read
|
The last case of entity, <code>Result</code>, serves to denote, within the body of a function, the final result to be returned by that function. This was illustrated by the function <code>deposit_count</code>, which read
|
||||||
<code>
|
<code>
|
||||||
deposit_count: INTEGER
|
deposit_count: INTEGER
|
||||||
-- Number of deposits made since opening (provisional version)
|
-- Number of deposits made since opening (provisional version)
|
||||||
do
|
do
|
||||||
if all_deposits /= Void then
|
if all_deposits /= Void then
|
||||||
@@ -267,7 +267,7 @@ Following the principle of Uniform Access (mentioned earlier in the section ''Ob
|
|||||||
|
|
||||||
In the case of a routine with arguments -- procedure or function -- the routine will be declared, in its class, as
|
In the case of a routine with arguments -- procedure or function -- the routine will be declared, in its class, as
|
||||||
<code>
|
<code>
|
||||||
some_feature (formal_1: TYPE_1; ...)
|
some_feature (formal_1: TYPE_1; ...)
|
||||||
do
|
do
|
||||||
...
|
...
|
||||||
end
|
end
|
||||||
@@ -288,10 +288,11 @@ With the dot notation seen so far, this would imply that simple arithmetic opera
|
|||||||
instead of the usual
|
instead of the usual
|
||||||
<code>
|
<code>
|
||||||
i + j
|
i + j
|
||||||
|
|
||||||
</code>
|
</code>
|
||||||
This would be awkward. Infix and prefix features solve the problem, reconciling the object-oriented view of computation with common notational practices of mathematics. The addition function is declared in class <code>INTEGER</code> as
|
This would be awkward. Infix and prefix features solve the problem, reconciling the object-oriented view of computation with common notational practices of mathematics. The addition function is declared in class <code>INTEGER</code> as
|
||||||
<code>
|
<code>
|
||||||
infix "+" (other: INTEGER): INTEGER
|
infix "+" (other: INTEGER): INTEGER
|
||||||
do
|
do
|
||||||
...
|
...
|
||||||
end
|
end
|
||||||
@@ -572,7 +573,7 @@ At any time during the execution of a system, one object is the '''current objec
|
|||||||
|
|
||||||
appearing in the body of procedure <code>deposit</code> of class <code>ACCOUNT</code>, the name of the attribute <code>balance</code>, in both occurrences, denotes the <code>balance</code> field of the current object, assumed to be an instance of <code>ACCOUNT</code>. In the same way, the procedure body that we used for the creation procedure <code>make</code> in the <code>ACCOUNT1</code> variant
|
appearing in the body of procedure <code>deposit</code> of class <code>ACCOUNT</code>, the name of the attribute <code>balance</code>, in both occurrences, denotes the <code>balance</code> field of the current object, assumed to be an instance of <code>ACCOUNT</code>. In the same way, the procedure body that we used for the creation procedure <code>make</code> in the <code>ACCOUNT1</code> variant
|
||||||
<code>
|
<code>
|
||||||
make (sum: INTEGER)
|
make (sum: INTEGER)
|
||||||
-- Initialize account with sum .
|
-- Initialize account with sum .
|
||||||
do
|
do
|
||||||
deposit (sum)
|
deposit (sum)
|
||||||
@@ -610,7 +611,7 @@ Restricting assignment targets to entities precludes assignments of the form <co
|
|||||||
|
|
||||||
To obtain the intended effect of such an assignment you may use a procedure call of the form <code>obj.set_attribute (some_value)</code> , where the base class of <code>obj</code>'s type has defined the procedure
|
To obtain the intended effect of such an assignment you may use a procedure call of the form <code>obj.set_attribute (some_value)</code> , where the base class of <code>obj</code>'s type has defined the procedure
|
||||||
<code>
|
<code>
|
||||||
set_attribute (v: VALUE_TYPE)
|
set_attribute (v: VALUE_TYPE)
|
||||||
-- Set value of attribute to v.
|
-- Set value of attribute to v.
|
||||||
do
|
do
|
||||||
attribute := v
|
attribute := v
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Eiffel software texts are free-format: distribution into lines is not semantical
|
|||||||
|
|
||||||
Successive declarations or instructions may be separated by semicolons. Eiffel's syntax has been so designed, however, that (except in rare cases) '''the semicolon is optional'''. Omitting semicolons for elements appearing on separate lines lightens text and is the recommended practice since semicolons, as used by most programming languages, just obscure the text by distracting attention from the actual contents. Do use semicolons if you occasionally include successive elements on a single line.
|
Successive declarations or instructions may be separated by semicolons. Eiffel's syntax has been so designed, however, that (except in rare cases) '''the semicolon is optional'''. Omitting semicolons for elements appearing on separate lines lightens text and is the recommended practice since semicolons, as used by most programming languages, just obscure the text by distracting attention from the actual contents. Do use semicolons if you occasionally include successive elements on a single line.
|
||||||
|
|
||||||
56 names -- all unabbreviated single English words, except for <code> elseif </code> which is made of two words -- are reserved, meaning that you cannot use them to declare new entities. Here is the list:
|
56 names -- all unabbreviated single English words, except for <code>elseif</code> which is made of two words -- are reserved, meaning that you cannot use them to declare new entities. Here is the list:
|
||||||
{| border="1"
|
{| border="1"
|
||||||
|-
|
|-
|
||||||
| <code>agent</code>
|
| <code>agent</code>
|
||||||
@@ -76,25 +76,25 @@ Successive declarations or instructions may be separated by semicolons. Eiffel's
|
|||||||
|
|
||||||
Since this tutorial has covered all the essential mechanisms, you may ignore the keywords not encountered; they are reserved for future use.
|
Since this tutorial has covered all the essential mechanisms, you may ignore the keywords not encountered; they are reserved for future use.
|
||||||
|
|
||||||
Most of the reserved words are keywords, serving only as syntactic markers, and written in boldface in typeset texts such as the present one: <code> class </code>, <code> feature </code>, <code> inherit </code>. The others, such as <code> Current </code>, directly carry a semantic denotation; they start with an upper-case letter and are typeset in boldface.
|
Most of the reserved words are keywords, serving only as syntactic markers, and written in boldface in typeset texts such as the present one: <code>class</code>, <code>feature</code>, <code>inherit</code>. The others, such as <code>Current</code>, directly carry a semantic denotation; they start with an upper-case letter and are typeset in boldface.
|
||||||
|
|
||||||
These conventions about letter case are only style rules. Eiffel is case-insensitive, since it is foolish to assume that two identifiers denote two different things just on the basis of a letter written in lower or upper case. The obvious exception is manifest character constants (appearing in single quotes, such as <code> 'A' </code>) and manifest character strings (appearing in double quotes, such as <code> "UPPER and lower" </code>).
|
These conventions about letter case are only style rules. Eiffel is case-insensitive, since it is foolish to assume that two identifiers denote two different things just on the basis of a letter written in lower or upper case. The obvious exception is manifest character constants (appearing in single quotes, such as <code>'A'</code>) and manifest character strings (appearing in double quotes, such as <code>"UPPER and lower"</code>).
|
||||||
|
|
||||||
The style rules, however, are precise, and any serious Eiffel project will enforce them; the tools of EiffelStudio also observe them in the texts they output (although they will not mess up with your source text unless you ask them to reformat it). Here are the conventions, illustrated by the examples of this tutorial:
|
The style rules, however, are precise, and any serious Eiffel project will enforce them; the tools of EiffelStudio also observe them in the texts they output (although they will not mess up with your source text unless you ask them to reformat it). Here are the conventions, illustrated by the examples of this tutorial:
|
||||||
* Class names in upper case, as <code> ACCOUNT </code>.
|
* Class names in upper case, as <code>ACCOUNT</code>.
|
||||||
* Non-constant feature names and keywords in lower case, as <code> balance </code> and <code> class </code>.
|
* Non-constant feature names and keywords in lower case, as <code>balance</code> and <code>class</code>.
|
||||||
* Constant features and predefined entities and expressions with an initial upper case, as <code> Avogadro </code> and <code> Result </code>.
|
* Constant features and predefined entities and expressions with an initial upper case, as <code>Avogadro</code> and <code>Result</code>.
|
||||||
|
|
||||||
In typeset documents including Eiffel texts, the standard for font styles is also precise. You should use <code> bold face </code> for keywords and <code> italics </code> for all other Eiffel elements. Comments, however, are typeset in <code> roman </code>. This lets a software element, such as an identifier, stand out clearly in what is otherwise a comment text expressed in English or another human language, as in the earlier example
|
In typeset documents including Eiffel texts, the standard for font styles is also precise. You should use <code>bold face</code> for keywords and <code>italics</code> for all other Eiffel elements. Comments, however, are typeset in <code>roman</code>. This lets a software element, such as an identifier, stand out clearly in what is otherwise a comment text expressed in English or another human language, as in the earlier example
|
||||||
<code>
|
<code>
|
||||||
-- Add `sum' to account.
|
-- Add `sum' to account.
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
which makes clear that <code> sum </code> is a software element, not the English word.
|
which makes clear that <code>sum</code> is a software element, not the English word.
|
||||||
|
|
||||||
There is also an Eiffel style to the choice of identifiers. For features, stay away from abbreviations and use full words. In multi-word identifiers, separate the constituents by underscores, as in <code> LINKED_LIST </code> and <code> set_owner </code>. The competing style of no separation but mid-identifier upper-case, as in <code> linkedList </code> or <code> setOwner </code>, is less readable and not in line with standard Eiffel practices.
|
There is also an Eiffel style to the choice of identifiers. For features, stay away from abbreviations and use full words. In multi-word identifiers, separate the constituents by underscores, as in <code>LINKED_LIST</code> and <code>set_owner</code>. The competing style of no separation but mid-identifier upper-case, as in <code>linkedList</code> or <code>setOwner</code>, is less readable and not in line with standard Eiffel practices.
|
||||||
|
|
||||||
Features of reusable classes should use consistent names. A set of standard names -- <code> put </code> for the basic command to add or replace an element, <code> count </code> for the query that returns the number of element in a structure, <code> item </code> to access an element -- is part of the style rules, and used systematically in EiffelBase. Use them in your classes too.
|
Features of reusable classes should use consistent names. A set of standard names -- <code>put</code> for the basic command to add or replace an element, <code>count</code> for the query that returns the number of element in a structure, <code>item</code> to access an element -- is part of the style rules, and used systematically in EiffelBase. Use them in your classes too.
|
||||||
|
|
||||||
For local entities and formal arguments of routines, it is all right to use abbreviated names, since these identifiers only have a local scope, and choosing a loud name would give them too much pretense, leading to potential conflicts with features.
|
For local entities and formal arguments of routines, it is all right to use abbreviated names, since these identifiers only have a local scope, and choosing a loud name would give them too much pretense, leading to potential conflicts with features.
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ Eiffel addresses this need through an original mechanism that also takes care of
|
|||||||
|
|
||||||
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>
|
<code>
|
||||||
setup
|
setup
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
at the beginning of each affected routine; the first one to come in will perform the needed initializations; subsequent calls will have, as desired, no effect.
|
at the beginning of each affected routine; the first one to come in will perform the needed initializations; subsequent calls will have, as desired, no effect.
|
||||||
|
|
||||||
Once functions will give us shared objects. A common scheme is
|
Once functions will give us shared objects. A common scheme is
|
||||||
<code>
|
<code>
|
||||||
console: WINDOW is
|
console: WINDOW
|
||||||
-- Shared console window
|
-- Shared console window
|
||||||
once
|
once
|
||||||
create Result.make (...)
|
create Result.make (...)
|
||||||
@@ -38,16 +38,16 @@ The attributes studied earlier were variable: each represents a field present in
|
|||||||
|
|
||||||
It is also possible to declare constant attributes, as in
|
It is also possible to declare constant attributes, as in
|
||||||
<code>
|
<code>
|
||||||
Solar_system_planet_count: INTEGER is 9
|
Solar_system_planet_count: INTEGER = 9
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
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.)
|
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>=</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
|
For integer constants, it is also possible to avoid specifying the values. A declaration of the form
|
||||||
<code>
|
<code>
|
||||||
a, b, c, ... n : INTEGER is unique
|
a, b, c, ... n : INTEGER = unique
|
||||||
</code>
|
</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.)
|
||||||
@@ -56,12 +56,12 @@ You may use Unique values in conjunction with the <code>inspect</code> multi-bra
|
|||||||
|
|
||||||
Manifest constants are also available for strings, using double quotes as in
|
Manifest constants are also available for strings, using double quotes as in
|
||||||
<code>
|
<code>
|
||||||
User_friendly_error_message: STRING is "Go get a life !"
|
User_friendly_error_message: STRING is "Go get a life !"
|
||||||
</code>
|
</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>
|
<code>
|
||||||
<<1, 2, 3, 5, 7, 11, 13, 17, 19>>
|
<<1, 2, 3, 5, 7, 11, 13, 17, 19>>
|
||||||
</code>
|
</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.
|
||||||
@@ -70,23 +70,33 @@ which is an expression of type <code>ARRAY [INTEGER]</code>. Manifest arrays and
|
|||||||
|
|
||||||
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.
|
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 ... then
|
||||||
|
...
|
||||||
|
elseif ... then
|
||||||
|
...
|
||||||
|
else
|
||||||
|
...
|
||||||
|
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
|
A multi-branch instruction has the form
|
||||||
<code>
|
<code>
|
||||||
inspect
|
inspect
|
||||||
''exp''
|
''exp''
|
||||||
when ''v1'' then
|
when ''v1'' then
|
||||||
''inst1''
|
''inst1''
|
||||||
when ''v2'' then
|
when ''v2'' then
|
||||||
''inst2''
|
''inst2''
|
||||||
...
|
...
|
||||||
else
|
else
|
||||||
''inst0''
|
''inst0''
|
||||||
end
|
end
|
||||||
</code>
|
</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 ''inst0''</code> 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.
|
||||||
|
|
||||||
@@ -94,17 +104,17 @@ The effect of such a multi-branch instruction, if the value of <code>exp</code>
|
|||||||
|
|
||||||
The loop construct has the form
|
The loop construct has the form
|
||||||
<code>
|
<code>
|
||||||
from
|
from
|
||||||
''initialization''
|
''initialization''
|
||||||
until
|
until
|
||||||
''exit''
|
''exit''
|
||||||
invariant
|
invariant
|
||||||
''inv''
|
''inv''
|
||||||
variant
|
variant
|
||||||
''var''
|
''var''
|
||||||
loop
|
loop
|
||||||
''body''
|
''body''
|
||||||
end
|
end
|
||||||
</code>
|
</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.
|
||||||
@@ -113,13 +123,18 @@ The effect is to execute ''initialization'', then, zero or more times until ''ex
|
|||||||
|
|
||||||
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.
|
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™. 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™. The instruction
|
||||||
|
<code>
|
||||||
|
check
|
||||||
|
Assertion
|
||||||
|
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>
|
<code>
|
||||||
r (ref: SOME_REFERENCE_TYPE) is
|
r (ref: SOME_REFERENCE_TYPE)
|
||||||
require
|
require
|
||||||
not_void: ref /= Void
|
not_void: ref /= Void
|
||||||
do
|
do
|
||||||
@@ -130,17 +145,19 @@ r (ref: SOME_REFERENCE_TYPE) is
|
|||||||
|
|
||||||
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>
|
<code>
|
||||||
if x /= Void then a.r (x) end
|
if x /= Void then
|
||||||
|
a.r (x)
|
||||||
|
end
|
||||||
</code>
|
</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>
|
<code>
|
||||||
check
|
check
|
||||||
x_not_void: x /= Void end
|
x_not_void: x /= Void end
|
||||||
-- Because x was obtained as a clone of y,
|
-- Because x was obtained as a clone of y,
|
||||||
-- and y is not void because [etc.]
|
-- and y is not void because [etc.]
|
||||||
end
|
end
|
||||||
a.r (x)
|
a.r (x)
|
||||||
</code>
|
</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. }}
|
||||||
@@ -155,7 +172,7 @@ This raises the issue of backward compatibility: how to move forward with a bett
|
|||||||
|
|
||||||
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>
|
<code>
|
||||||
enter (i: INTEGER; x: G) is
|
enter (i: INTEGER; x: G)
|
||||||
obsolete
|
obsolete
|
||||||
"Use ` put (x, i)' instead "
|
"Use ` put (x, i)' instead "
|
||||||
require
|
require
|
||||||
@@ -182,20 +199,20 @@ The design flexibility afforded by the <code>obsolete</code> keyword is critical
|
|||||||
|
|
||||||
The basic forms of creation instruction, and the one most commonly used, are the two illustrated earlier ( [[6 The Dynamic Structure: Execution Model|"Creating and initializing objects", page 20]] ):
|
The basic forms of creation instruction, and the one most commonly used, are the two illustrated earlier ( [[6 The Dynamic Structure: Execution Model|"Creating and initializing objects", page 20]] ):
|
||||||
<code>
|
<code>
|
||||||
create x.make (2000)
|
create x.make (2000)
|
||||||
create x
|
create x
|
||||||
</code>
|
</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>
|
<code>
|
||||||
create {SAVINGS_ACCOUNT} x.make (2000)
|
create {SAVINGS_ACCOUNT} x.make (2000)
|
||||||
</code>
|
</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>
|
<code>
|
||||||
local
|
local
|
||||||
xs: SAVINGS_ACCOUNT
|
xs: SAVINGS_ACCOUNT
|
||||||
do
|
do
|
||||||
create xs.make (2000)
|
create xs.make (2000)
|
||||||
x := xs
|
x := xs
|
||||||
...
|
...
|
||||||
@@ -203,14 +220,14 @@ do
|
|||||||
|
|
||||||
and has exactly the same effect. Another variant is the '''creation expression''', which always lists the type, but returns a value instead of being an instruction. It is useful in the following context:
|
and has exactly the same effect. Another variant is the '''creation expression''', which always lists the type, but returns a value instead of being an instruction. It is useful in the following context:
|
||||||
<code>
|
<code>
|
||||||
some_routine (create {ACCOUNT}.make (2000))
|
some_routine (create {ACCOUNT}.make (2000))
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
which you may again view as an abbreviation for a more verbose form that would need a local entity, using a creation instruction:
|
which you may again view as an abbreviation for a more verbose form that would need a local entity, using a creation instruction:
|
||||||
<code>
|
<code>
|
||||||
local
|
local
|
||||||
x: ACCOUNT
|
x: ACCOUNT
|
||||||
do
|
do
|
||||||
create x.make (2000)
|
create x.make (2000)
|
||||||
some_routine (x)
|
some_routine (x)
|
||||||
...
|
...
|
||||||
@@ -222,7 +239,7 @@ The creation mechanism gets an extra degree of flexibility through the notion of
|
|||||||
|
|
||||||
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>
|
<code>
|
||||||
[G -> T create cp end]
|
[G -> T create cp end]
|
||||||
</code>
|
</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>.
|
||||||
@@ -231,7 +248,7 @@ to make <code>G</code> constrained by <code>T</code>, as we learned before, and
|
|||||||
|
|
||||||
The study of genericity described arrays. Another common kind of container objects bears some resemblance to arrays: sequences, or "tuples", of elements of specified types. The difference is that all elements of an array were of the same type, or a conforming one, whereas for tuples you will specify the types we want for each relevant element. A typical tuple type is of the form
|
The study of genericity described arrays. Another common kind of container objects bears some resemblance to arrays: sequences, or "tuples", of elements of specified types. The difference is that all elements of an array were of the same type, or a conforming one, whereas for tuples you will specify the types we want for each relevant element. A typical tuple type is of the form
|
||||||
<code>
|
<code>
|
||||||
TUPLE [X, Y, Z]
|
TUPLE [X, Y, Z]
|
||||||
</code>
|
</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>.
|
||||||
@@ -242,7 +259,7 @@ You may list any number of types in brackets, including none at all: <code>TUPLE
|
|||||||
|
|
||||||
To write the tuples themselves -- the sequences of elements, instances of a tuple type -- you will also use square brackets; for example
|
To write the tuples themselves -- the sequences of elements, instances of a tuple type -- you will also use square brackets; for example
|
||||||
<code>
|
<code>
|
||||||
[x1, y1, z1]
|
[x1, y1, z1]
|
||||||
</code>
|
</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>.
|
||||||
@@ -253,8 +270,7 @@ Features available on tuple types include <code>count: INTEGER</code>, yielding
|
|||||||
|
|
||||||
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>
|
<code>
|
||||||
|
write ([your_integer, your_real, your_account])
|
||||||
write ([ ''your_integer'' , ''your_real'', ''your_account''])
|
|
||||||
</code>
|
</code>
|
||||||
|
|
||||||
As soon as you need a type with more specific features, you should define a class.
|
As soon as you need a type with more specific features, you should define a class.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Above classes, you will find the concept of cluster. A cluster is a group of rel
|
|||||||
|
|
||||||
The subsequent sections will show how to write Eiffel classes with their features. In an Eiffel system, however, not everything has to be written in Eiffel: some features may be '''external''' , coming from languages such as C, C++, Java, C# Fortran and others. For example a feature declaration may appear (in lieu of the forms seen later) as
|
The subsequent sections will show how to write Eiffel classes with their features. In an Eiffel system, however, not everything has to be written in Eiffel: some features may be '''external''' , coming from languages such as C, C++, Java, C# Fortran and others. For example a feature declaration may appear (in lieu of the forms seen later) as
|
||||||
<code>
|
<code>
|
||||||
file_status (filedesc: INTEGER): INTEGER
|
file_status (filedesc: INTEGER): INTEGER
|
||||||
-- Status indicator for filedesc
|
-- Status indicator for filedesc
|
||||||
external
|
external
|
||||||
"C" alias "_fstat"
|
"C" alias "_fstat"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
[[Property:title|Once features in multithreaded mode]]
|
[[Property:title|Once features in multithreaded mode]]
|
||||||
[[Property:weight|4]]
|
[[Property:weight|4]]
|
||||||
|
[[Property:uuid|5578da29-7603-b501-1a7d-305d20fd6485]]
|
||||||
==Manipulating Once features in multithreaded mode==
|
==Manipulating Once features in multithreaded mode==
|
||||||
|
|
||||||
Eiffel introduced the powerful mechanism of once routines. A once routine has a body that will be executed only once, at the first call. Subsequent calls will have no further effect and, in the case of a function, will return the same result as the first. This provides a simple way of sharing objects in an object-oriented context.
|
Eiffel introduced the powerful mechanism of once routines. A once routine has a body that will be executed only once, at the first call. Subsequent calls will have no further effect and, in the case of a function, will return the same result as the first. This provides a simple way of sharing objects in an object-oriented context.
|
||||||
@@ -23,7 +24,7 @@ Here is what you will do to implement a once per process feature:
|
|||||||
class
|
class
|
||||||
TEST_ONCE_PER_PROCESS
|
TEST_ONCE_PER_PROCESS
|
||||||
|
|
||||||
feature
|
feature -- Access
|
||||||
|
|
||||||
object_per_thread: OBJECT is
|
object_per_thread: OBJECT is
|
||||||
-- Once per thread.
|
-- Once per thread.
|
||||||
@@ -41,7 +42,7 @@ class
|
|||||||
create Result.make
|
create Result.make
|
||||||
end
|
end
|
||||||
|
|
||||||
end -- class TEST_ONCE_PER_PROCESS
|
end -- class TEST_ONCE_PER_PROCESS
|
||||||
</code>
|
</code>
|
||||||
You can do the same with once procedures.
|
You can do the same with once procedures.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user