Author:bmeyer

Date:2014-02-12T17:17:34.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1260 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
bmeyer
2014-02-12 17:17:34 +00:00
parent 10bfd79ee3
commit ab3d8466ba

View File

@@ -5,7 +5,7 @@ The classes of the Iteration cluster encapsulate control structures representing
=Iterators and Agents=
The recent introduction of the agents mechanism in Eiffel offers an attractive alternative to the <eiffel>Iterator</eiffel> cluster of EiffelBase.
Eiffel's agent mechanism offers an attractive alternative to the <eiffel>Iterator</eiffel> cluster of EiffelBase.
=The Notion of iterator=
@@ -51,18 +51,13 @@ The classes of the Iteration library address this need. Using them offers two be
=Simple Examples=
To get a first grasp of how one can work with the Iteration library, let us look at a typical iteration class and a typical iteration client.
==An example iterator routine==
Here, given with its full implementation, is a typical Iteration library routine: the procedure until_do from [[ref:libraries/base/reference/linear_iterator_chart]] , the class defining iteration mechanisms on linear (sequential) structures.
<code>
until_do
until_do
-- Apply action to every item of target,
-- up to but excluding first one satisfying test.
-- (Apply to full list if no item satisfies test.)
@@ -89,7 +84,7 @@ This procedure will traverse the linear structure identified by target and apply
The class similarly offers <eiffel>do_all</eiffel>, <eiffel>do_while</eiffel>, <eiffel>do_for</eiffel>, <eiffel>do_if</eiffel> and other procedures representing the common control structures. It also includes functions such as <eiffel>exists</eiffel> and <eiffel>forall</eiffel>, corresponding to the usual quantifiers. <br/>
These iteration schemes depend on the procedure <eiffel>action</eiffel>, defining the action to be applied to successive elements, and on the function <eiffel>test</eiffel>, defining the boolean query to be applied to these elements. These features are declared in class [[ref:/libraries/base/reference/iterator_chart|ITERATOR]] (the highest-level deferred class of the Iteration library); here is <eiffel>test</eiffel>:
<code>
test: BOOLEAN
test: BOOLEAN
-- Test to be applied to item at current position in
-- target (default: value of item_test on item)
require
@@ -277,7 +272,6 @@ The class effects all the deferred features inherited from [[ref:/libraries/base
-- test.
do
from
target.start
invariant
invariant_value
@@ -303,7 +297,7 @@ This routine text relies on features <eiffel>start</eiffel>, <eiffel>forth</eiff
and similarly for the others. <br/>
In addition to effecting the general iteration features from [[ref:/libraries/base/reference/iterator_chart|ITERATOR]] , class [[ref:/libraries/base/reference/linear_iterator_chart|LINEAR_ITERATOR]] introduces iteration features that apply to the specific case of linear structures:
* <eiffel>search </eiffel> <code> ( b :BOOLEAN) moves the iteration to the first position satisfying test if b is true, or not satisfying test if b </code> is false. This use of a boolean argument to switch between two opposite semantics is not part of the recommended style, and you will find few if any other examples in the Base libraries. Here, however, it was deemed preferable to the alternative, which would have involved four separate procedures (if together with <eiffel>search</eiffel> we consider <eiffel>continue_search</eiffel> discussed next).
* <eiffel>search (b :BOOLEAN)</eiffel> moves the iteration to the first position satisfying test if <code>b</code> is true, or not satisfying test if <code>b</code> is false. This use of a boolean argument to switch between two opposite semantics is not part of the recommended style, and you will find few if any other examples in the Base libraries. Here, however, it was deemed preferable to the alternative, which would have involved four separate procedures (if together with <eiffel>search</eiffel> we consider <eiffel>continue_search</eiffel> discussed next).
* With a linear structure we can implement an iteration corresponding to the 'for' loop of traditional programming languages, defined by three integers: the starting position, the number of items to be traversed, and the step between consecutive items. This is provided by procedure <eiffel>do_for</eiffel> <code> ( starting , number , step :INTEGER). </code>
* Since with a linear target the iterator can advance the cursor step by step, the basic iteration operations are complemented by variants which pick up from the position reached by the last call: <eiffel>continue_until</eiffel>, <eiffel>until_continue</eiffel>, <eiffel>continue_while</eiffel>, <eiffel>while_continue</eiffel>, <eiffel>continue_search</eiffel>, <eiffel>continue_for</eiffel>.
@@ -379,7 +373,7 @@ feature -- Cursor movement
target.back
end
end
</code>
</code>
This class provides a good example of the economy of expression that the full inheritance mechanism affords through the combination of renaming, redefinition, repeated inheritance rules and selection, without sacrificing clarity and maintainability.
@@ -475,7 +469,7 @@ feature
...
end
</code>
</code>
The repeated inheritance machinery takes care of the rest.
@@ -494,7 +488,7 @@ inherit
feature
...
end
</code>
</code>
In the feature clause we want to provide the appropriate effectings for the deferred features of class <eiffel>FIGURE</eiffel>: <eiffel>display</eiffel>, <eiffel>hide</eiffel>, <eiffel>translate</eiffel> and all other basic figure operations. <br/>
We can use loops for that purpose, for example
@@ -512,7 +506,7 @@ We can use loops for that purpose, for example
forth
end
end
</code>
</code>
Although acceptable and even elegant, this scheme will cause significant duplication: all the <eiffel>FIGURE</eiffel> features - not just <eiffel>display</eiffel> but also <eiffel>hide</eiffel>, <eiffel>rotate</eiffel>, <eiffel>move</eiffel> and others - will have the same structure, with a loop. We can use iterators to avoid this duplication. The repeated inheritance technique would work, but given the large number of <eiffel>FIGURE</eiffel> features the amount of repeated inheritance that would be needed seems unwieldy. It is also not very desirable to have to change the inheritance structure of the system just to add a new feature to <eiffel>FIGURE</eiffel>. The more dynamic approach using iterator objects seems preferable. <br/>
To implement this approach, define a class for iterating on complex figures:
@@ -534,7 +528,7 @@ feature
target: COMPLEX_FIGURE
end
</code>
</code>
Then for each operation to be iterated define a small class. For example:
<code>
@@ -559,7 +553,7 @@ feature
f.display
end
end
</code>
</code>
Similarly, you may define <eiffel>FIGURE_HIDER</eiffel>, <eiffel>FIGURE_MOVER</eiffel> and others. Then the features of <eiffel>COMPLEX_FIGURE</eiffel> are written almost trivially, without any explicit loops; for example:
<code>
@@ -572,10 +566,10 @@ Similarly, you may define <eiffel>FIGURE_HIDER</eiffel>, <eiffel>FIGURE_MOVER</e
create disp.set (Current)
disp.do_all
end
</code>
</code>
and similarly for all the others. <br/>
Note the use of <eiffel>set</eiffel> as creation procedure, which is more convenient than requiring the clients first to create an iterator object and then to call <eiffel>set</eiffel>. This is also safer, since with <eiffel>set</eiffel> as a creation procedure the client cannot forget to initialize the target. (If a class <eiffel>C</eiffel> has a creation clause, the creation instruction <code> create </code> <eiffel>C</eiffel>.)
Note the use of <eiffel>set</eiffel> as creation procedure, which is more convenient than requiring the clients first to create an iterator object and then to call <eiffel>set</eiffel>. This is also safer, since with <eiffel>set</eiffel> as a creation procedure the client cannot forget to initialize the target. (If a class <eiffel>C</eiffel> has a creation clause, the creation instruction <code>create </code> <eiffel>C</eiffel>.)