[[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 if ... then ... elseif ... then ... else ... end The elseif ... then ... part (of which there may be more than one) and the else ... part are optional. After if and elseif comes a boolean expression; after then and else come zero or more instructions. ===Multi-branch=== A multi-branch instruction has the form inspect exp when v1 then inst when v2 then inst2 ... else inst0 end where the else inst0 part is optional, exp is a character or integer expression, v1, v1, ... are constant values of the same type as exp, all different, and inst0, inst1, inst2, ... are sequences of zero or more instructions. The effect of such a multi-branch instruction, if the value of exp 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 else part, in which case it triggers an exception. {{note|Raising an exception is the proper behavior, since the absence of an else 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 else part with an empty inst0. In contrast, if c then inst end with no else part does nothing in the absence of an else part, since in this case there is no implied claim that c must hold. }} ===Loop=== The loop construct provides a flexible framework for 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. ====Some examples==== First let's take a look at two examples. These examples both use a loop to visit and print the content of each node of a linked list of character strings. So, the list in question might be declared like this: my_list: LINKED_LIST [STRING] Now for the two loop examples: from my_list.start until my_list.off loop print (my_list.item) my_list.forth end ''Loop example 1.'' and: across my_list as ic loop print (ic.item) end ''Loop example 2.'' At first observation, it may not appear that both of these examples are using the same language construct. But, indeed, they are simply two different forms of a single language construct, as you will see. Of course, there is no requirement that ''Loop example 1'' occupy multiple lines, and ''Loop example 2'' occupy only one line. ''Loop example 1'' could have been written like this: from my_list.start until my_list.off loop print (my_list.item) my_list.forth end just as ''Loop example 2'' could have been written to take multiple lines. It comes down to a matter of balance among traditional style, conciseness, and readability. In fact, these two examples illustrate the two basic usage forms of the loop construct in Eiffel. The two basic forms can be differentiated by the parts of the construct with which they begin. The form shown in ''Loop example 1'' begins with an ''Initialization'' part ( from my_list.start ), which starts with the keyword from. Let's call this form the '''traditional''' form. So, the type of loop you see in ''Loop example 1'' has been the traditional mechanism for accomplishing iterative computation, including iterating across data structures. However, extensions to Eiffel's loop construct have provided a more concise way of expressing traversing "iterable" structures. This is the form shown in ''Loop example 2''. It begins with an ''Iteration'' part ( across my_list as c ), which starts with the keyword across. We'll call this form the '''iteration''' form. ====A closer look at the ''traditional'' form==== What is happening in ''Loop example 1''? Let's dissect it and see. First there is the ''initialization'' part: from my_list.start ''Initialization part.'' The first thing to occur in the execution of the traditional loop is the execution of any instructions in the initialization part (it is permissible for the initialization part to be empty of instructions, but the keyword from must be present to distinguish the traditional loop form). In our example, the feature start is applied to my_list which will attempt to set the list cursor to the first element in my_list. The ''Exit condition part'': until my_list.off ''Exit condition part.'' The exit condition part of the loop construct defines the conditions under which the loop body (explained below) should no longer be executed. In our example, the loop will no long execute if the cursor is "off", that is, there is no current item. So, if the list is empty, the loop body will not execute at all. The ''loop body'' part: loop print (my_list.item) my_list.forth ''loop body part.'' The loop body part contains the sequence of instructions to be executed during each iteration. In the example, that includes printing the current list item and then advancing the cursor. At some point, the cursor will pass the last item in the list, causing the exit condition to become true and stop the loop's execution. 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 is guaranteed always to cause the exit condition eventually to become true. Loop correctness will discussed in more detail later. And finally, there's the ''End'' part: end ''end part.'' ====A closer look at the ''iteration'' form==== Now let's examine the iteration form used in ''Loop example 2.'' The example begins with an iteration part: across my_list as ic ''Iteration part.'' 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 ITERABLE. The iteration part specifies such a target for the iteration, in the case of our example, the target is my_list. The "as ic" indicates that a local iteration cursor object referenced by the name ic, and available only for the scope of the iteration, will be created to effect the iteration. The element of my_list which is currently referenced by the cursor ic is accessed through ic.item as you see in the loop body: loop print (ic.item) ''loop body part''. And lastly, of course, the iteration form includes an ''end part'' ... at the end. Notice that the loop body does not contain the call to the structure's forth feature, as our example in traditional form did. Neither do you see the call to start nor the check of off in the exit condition. The iteration form abstracts these for you, relieving you of their burden ... while eliminating some opportunities for error. Notice also that the call "print (ic.item)"" accesses the current item as "ic.item"" versus "my_list.item"" in the traditional form. This is because in the iteration form, access to the current item is through the cursor variable, "ic" in the case of ''Loop example 2''. 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 LINKED_LIST [STRING] called my_list. Applying the feature item to my_list retrieves the list element currently referenced by the cursor. In the iteration version of traversal, the variable ic holds the iteration cursor, external to the list object. So, you apply ic.item 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. ====The ''iteration'' form as a boolean expression==== In ''Loop example 2'', the loop behaves as an instruction. But it is possible to have the iteration loop form behave as a boolean expression. This is helpful in cases in which you might want to ask a question that can be answered by traversing all or part of a structure. To get this effect, you use the iteration form with one of two alternative body notations, the ''all body part'' or the ''some body part'' in place of the ''loop body''. When you use either of these notations, the ''body'' is a boolean expression. So, the forms for these body parts are: all boolean_expression ''all body part.'' some boolean_expression ''some body part.'' So, to know if all the strings in my_list have lengths greater than three characters, we could code: across my_list as ic all ic.item.count > 3 end ''Loop example 3.'' To know if at least one string in my_list has a length greater than three characters, we would use the ''some body part'': across my_list as ic some ic.item.count > 3 end ''Loop example 4.'' Of course you can use loops like the two above as you would any boolean expression, in a [[#Conditional|conditional]], for example. ====Loop anatomy and validity==== Now that we've seen examples of the two forms of loops and broken down their component parts, we're ready to examine the anatomy of the entire construct. You may remember from the beginning of this discussion of loops that the flexibility of the construct lies in its ability to use or omit its various parts to gain certain effects. Here are all the possible loop parts, most of which we've seen in examples, in the order in which they must appear when we code them: {| border="2" ! This loop part: !! Looks like this: |- | ''Iteration part'' || across my_list as ic |- | ''Initialization part'' || from my_list.start |- | ''Invariant part'' |- | ''Exit condition part'' || until my_list.off |- | ''Body part'' || loop ''zero_or_more_instructions '' '''or''' |- | || all ''a_boolean_expression '' '''or''' |- | || some ''a_boolean_expression'' |- | ''Variant part'' |- | ''end part'' || end |} ====Loop invariants and variants==== ===Debug=== An occasionally useful instruction is debug (''Debug_key'', ... ) ''instructions'' end 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 debug compilation option: yes, no, 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™. The instruction check Assertion end where Assertion is a sequence of zero or more assertions, will have no effect unless assertion monitoring is turned on at the Check 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 check 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 r (ref: SOME_REFERENCE_TYPE) require not_void: ref /= Void do ref.some_feature ... end Because of the call to some_feature, 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 if x /= Void then a.r (x) end but this is not the only possible scheme; for example if an create x appears shortly before the call we know x is not void and do not need the protection. It is a good idea in such cases to use a check 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 x could have been obtained, somewhere else in the algorithm, as clone (y) for some y that you know is not void. You should document this knowledge by writing the call as 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) {{recommended|An extra indentation of the check 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.