Files
eiffel-org/documentation/current/method/eiffel-tutorial-et/et-instructions.wiki
halw 1e05b9bbcf Author:halw
Date:2010-02-04T22:27:19.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@437 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
2010-02-04 22:27:19 +00:00

164 lines
12 KiB
Plaintext

[[Property:title|ET: Instructions (beta)]]
[[Property:link_title|ET: Instructions]]
[[Property:weight|-6]]
[[Property:uuid|628bf3db-728f-0b3c-bdbb-fe52deaae5b7]]
==Instructions==
Eiffel has a remarkably small set of instructions. The basic computational instructions have been seen: creation, assignment, assignment attempt, procedure call, retry. They are complemented by control structures: conditional, multi-branch, loop, as well as debug and check.
===Conditional===
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> and <code>else</code> come zero or more instructions.
===Multi-branch===
A multi-branch instruction has the form
<code>
inspect
exp
when v1 then
inst
when v2 then
inst2
...
else
inst0
end
</code>
where the <code>else inst0</code> part is optional, <code>exp</code> is a character or integer expression, <code>v1</code>, <code>v1</code>, ... are constant values of the same type as <code>exp</code>, all different, and <code>inst0</code>, <code>inst1</code>, <code>inst2</code>, ... are sequences of zero or more instructions.
The effect of such a multi-branch instruction, if the value of <code>exp</code> is one of the <code>vi</code>, is to execute the corresponding <code>insti</code>. If none of the <code>vi</code> matches, the instruction executes <code>inst0</code>, unless there is no <code>else</code> part, in which case it triggers an exception.
{{note|Raising an exception is the proper behavior, since the absence of an <code>else</code> indicates that the author asserts that one of the values will match. If you want an instruction that does nothing in this case, rather than cause an exception, use an <code>else</code> part with an empty <code>inst0</code>. In contrast, <code>if c then</code> <code>inst</code> <code>end</code> with no <code>else</code> part does nothing in the absence of an <code>else</code> part, since in this case there is no implied claim that <code>c</code> must hold. }}
===Loop===
The loop construct provides a flexible framework for doing iterative computation. Its flexibility lies in how the complete form can be tailored and simplified for certain purposes by omitting optional parts. We will explore the entire mechanism, but let's approach things a little at a time.
First let's look at the loop in what is probably its most common usage. This is a case in which some parts of the loop construct have been omitted because they are not necessary. So, just remember that what you are seeing in this example is not everything that loops can be.
<code>
from
Initialization
until
Exit_condition
loop
Loop_body
end
</code>
<code>Initialization</code> and <code>Loop_body</code> are sequences of zero or more instructions; <code>Exit_condition</code> is a boolean expression.
The effect is to execute <code>Initialization</code>, then, zero or more times until <code>Exit_condition</code> is satisfied, to execute <code>Loop_body</code>. (If after <code>Initialization</code> the value of <code>Exit_condition</code> is already true, <code>Loop_body</code> will not be executed at all.) So, at the risk of stating the obvious, the key to loops that always complete is to ensure that there is something in the loop body that will always cause the exit condition eventually to become true.
This form of the loop is used commonly to traverse data structures. For example, suppose that we wished to print every element in a linked list of strings. We can do so with this usage of the loop construct, as shown below.
<code>
my_list: LINKED_LIST [STRING]
...
from
my_list.start
until
my_list.off
loop
print (my_list.item)
my_list.forth
end
</code>
Loop example 1.
The <code>Initialization</code> part will attempt to set the cursor at the first item of the list. The loop will exit when there is no active list item. Then, in the <code>Loop_body</code>, the current list item will be printed, and the cursor advanced.
So, the usage of the loop construct in Loop example 1 above has been the traditional mechanism for traversing data structures. However, extensions to Eiffel's loop construct have provided a more concise way of expressing the same traversal:
<code>
across my_list as ic loop print (ic.item) end
</code>
Loop example 2.
Here the <code>across</code> indicates an iteration process across the structure <code>my_list</code>. The "<code>as ic</code>" indicates that an iteration cursor object referenced by the name <code>ic</code>, and available only for the scope of the iteration, will be created to effect the iteration. The element of <code>my_list</code> which is currently referenced by the cursor <code>ic</code> is <code>ic.item</code> as you see in the call to <code>print (ic.item)</code> in the loop body. The loop body does not contain the call to the structure's <code>forth</code> feature, as our more traditional example did. Neither do you see the call to <code>start</code> nor the check of <code>off</code> in the exit condition. The semantics of the iteration abstract these for you, relieving you of their burden ... while eliminating some opportunities for error.
Concerning cursors, both ways of using the loop construct to traverse a structure employ a cursor. In the traditional usage, the cursor is internal to the structure object. In the case of the example, that would be the instance of <code>LINKED_LIST [STRING]</code> called <code>my_list</code>. Applying the feature <code>item</code> to <code>my_list</code> retrieves the list element currently referenced by the cursor. In the iteration version of traversal, the variable <code>ic</code> holds the iteration cursor, external to the list object. So, you apply <code>ic.item</code> to get the current list element. The advantage to the external cursor is that multiple traversals of the structure can occur simultaneously without interfering with one another. This is possible in the traditional usage, but only by saving and restoring the structure's cursor.
At first observation, it may not appear that both traversal examples are using the same language construct. But, indeed they are simply two different forms of a single language construct. In order to see this more clearly, it will help now to examine the specific parts of the loop construct.
====Two basic loop forms====
The two basic forms of use of the Eiffel loop construct can be differentiated by the parts of the construct with which they begin.
The form shown in Loop example 1 above begins with an ''Initialization'' part ( <code>from my_list.start</code> ). Let's call this form the ''traditional'' form.
The form shown in Loop example 2 above begins with an ''Iteration'' part ( <code>across my_list as c</code> ). We'll call this form the ''iteration'' form.
The iteration form is special in the sense that it is designed to work with objects which are ''iterable'', usually data structures. The iteration form always targets a particular object, usually a data structure, based on a class that inherits, either directly or indirectly from the library class <code>ITERABLE</code>.
Every valid loop must have at least an ''initialization'' part or ''iteration'' part. An ''iteration'' part always precedes an ''initialization'' part. So, it is possible for loops in the iteration form (but not possible for traditional loops) to have both. Suppose we wanted to compute the sum of the lengths of all the strings in the list <code>my_list</code>. We could write an iteration loop with an initialization setting the sum to zero:
<code>
across my_list as ic from sum := 0 loop sum := sum + ic.item.count end
</code>
Loop example 3.
===Debug===
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.
===Check===
The final instruction is connected with Design by Contract&#153;. 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
<code>
r (ref: SOME_REFERENCE_TYPE)
require
not_void: ref /= Void
do
ref.some_feature
...
end
</code>
Because of the call to <code>some_feature</code>, the routine will only work if its precondition is satisfied on entry. To guarantee this precondition, the caller may protect it by the corresponding test, as in
<code>
if x /= Void then
a.r (x)
end
</code>
but this is not the only possible scheme; for example if an <code>create x</code> appears shortly before the call we know <code>x</code> is not void and do not need the protection. It is a good idea in such cases to use a <code>check</code> instruction to document this property, if only to make sure that a reader of the code will realize that the omission of an explicit test (justified or not) was not a mistake. This is particularly appropriate if the justification for not testing the precondition is less obvious. For example <code>x</code> could have been obtained, somewhere else in the algorithm, as <code>clone (y)</code> for some <code>y</code> that you know is not void. You should document this knowledge by writing the call as
<code>
check
x_not_void: x /= Void
-- Because x was obtained as a clone of y,
-- and y is not void because [etc.]
end
a.r (x)
</code>
{{recommended|An extra indentation of the <code>check</code> part to separate it from the algorithm proper; and inclusion of a comment listing the rationale behind the developer's decision not to check explicitly for the precondition. }}
In production mode with assertion monitoring turned off, this instruction will have no effect. But it will be precious for a maintainer of the software who is trying to figure out what it does, and in the process to reconstruct the original developer's reasoning. (The maintainer might of course be the same person as the developer, six months later.) And if the rationale is wrong somewhere, turning assertion checking on will immediately uncover the bug.