Loop - EndLoop

The four valid loop constructions are:

The lines of FISH between loop and endloop are executed repeatedly until certain conditions are met. Specific details of each loop option are given below:

Loops may be nested to any depth.

Indexed Loop

In the first form, which uses a numeric counter, var is given the value of expr1 initially, and is incremented by expr3 at the end of each loop execution until it reaches a value greater than expr2. If expr3 is not given, a value of 1 is used by default.

The local statement may optionally be used before var to create var as a variable local to the function.

Note that expr1, expr2, and expr3 (which may be arbitrary expressions) are evaluated at the start of the loop; redefinition of their component variables within the loop has no effect on the number of loop executions.

Also note that the comparison of var with the result of expr2 is done at the end of the loop, so the interior of the loop will always be executed at least once regardless of the values.

var is a genaral FISH variable; it may be used in expressions within the loop (even in functions called from within the loop, if it is a global variable), and may even be redefined. The increment of the value designated by expr3 is done in terms of the general FISH + operator, and the comparison with expr2 is done with the < operator. Any type(s) compatibile with those operators may be used,although most commonly the type used is an integer or a real.

The code snippet below demonstrates basic usage of this form to sum all integers below a specified value.

fish define sum(n)
    local s = 0
    loop local i (1,n)
        s += i  
    endloop
    sum = s
end
[s = sum(10)]
fish list [s]

fish define sum_even(n)
    local s = 0
    loop local i (0,n,2)
        s += i
    endloop
    sum_even = s
end
[s2 = sum_even(10)]
fish list [s2]

With n`=:lint:`10, the end result of the functions is s = 55 and s2 = 30. Note that the loop value may be an integer or a real, and by using a negative value for expr3 it may go from a larger to a smaller value.

While Loop

loop while exprtest

...

endloop

In the second form of the loop structure, the loop body is executed while the test expression evaluates to true; otherwise control passes to the next line after the endloop statement.

The expressions may involve floating-point variables as well as integers; the use of Boolean, strings and pointers is also permitted under the same conditions that apply to the if statement.

The code snippet below demonstrate basic usage of this form to sum all even integers below a specified value.

fish define sum_even(n)
    local s = 0
    local i = 0
    loop while i <= n
        s += i
        i +=2
    endloop
    sum_even = s
end
[s2 = sum_even(10)]
fish list [s2]

With n = 10, the end result of the sum is 30.

For Loop

loop for (exprinit, exprtest, exprmodify)

...

endloop

The main function of the third form of the loop structure is to repeat execution of the loop body while the test expression is true, similar to the loop while form. But, in addition, the loop for construct provides specific locations to contain an initialize field and a modify field. So this loop is specially designed to perform a repetitive action with a counter which is initialized and modified on each iteration. It works in the following way.

  1. Initialization is executed. Generally it is an initial value setting for a counter variable (which can be local or global). This is executed only once.

  2. Condition is checked. If it is true, the loop continues; otherwise, the loop ends and the loop body is not executed.

  3. Loop body is executed.

  4. Finally, whatever is specified in the modify field is executed, and the loop goes back to step 2.

The code snippet below demonstrate basic usage of this form to sum all odd integers below a specified value.

fish define sum_odd(n)
    local s= 0
    loop for (local i=1, i <=n, i+=2)
        s += i  
    endloop
    sum_odd = s
end
[s_odd = sum_odd(10)]
fish list [s_odd]

With n = 10, the end result of the sum is 25.

The first three forms of the loop statement may be contrasted. In the first, the test is done at the end of the loop (so there will be at least one pass through the loop); in the second and third, the test is done at the start of the loop (so the loop will be bypassed if the test is false initially).

ForEach Loop

loop foreach <local> var expr1

...

endloop

The fourth form of the loop statement is a specialized syntax to allow iterating through all objects inside a given iterable object. In this case, expr1 must evaluate to an iterable object, most commonly a pointer to a container or a list. For example, all scalars in the list of user-defined scalars are returned by the FISH intrinsic data.scalar.list.

As with the first loop form, var may be preceded by the local statement to indicate that a local variable is to be created instead of a global one. var will be assigned to each value in the iterable object consecutively.

If the object being looped over is a pointer to a container, and var is deleted during processing of the loop, the loop will continue normally as long as var is not referenced again within the same loop after deletion. If other items in the container are deleted (for example, if a function that deletes the contents of the container is called), then the loop might exit prematurely.

fish define scalar_location
    loop foreach local pnt data.scalar.list
        io.out(data.scalar.pos(pnt))
    endloop
end