Water 5-Flow Control and Boolean-Looping
method for_each
The only looping and iteration method in Water.
Contract
Return typewob
Parameter keyDefault valueType
includevector_keyvar
combinerreturn_first_argvar
excludenull
for_each_resultopt
foreverfalseboolean
Parameter kindDefault valueType
Other unkeyed argumentsopt with ekind of expressionwob
Water Contract
<method for_each
  include       =vector_key
  combiner      =return_first_arg
  exclude       =null
  for_each_result=opt
  forever       =false=boolean
  _other_unkeyed=opt=wob=ekind.expression="_body"/>

Why use for_each?

If you want to execute a body of code multiple times, perhaps with slight variations, without intervening code running, you have three choices:
    put the code in a method and call it once for each time you want to run ituse recursion, i.e. put the code in a method and have the code call that methoduse for_each
All these techniques are fine programming style in Water, though there are trade-offs. Technique 1 is ok when you have a small number of times to run the code and you know exactly how many there are when you write the code. Technique 2 is fine provided you're very careful not to have an infinite recursion and are willing to manage the data that varies each time around. Technique 3 gives you some high-level support for varying data, loop termination and collecting results. for_each let's you loop a given number of times, loop over the keys and values of objects and/or loop until a condition is met. In many situations, for_each is simpler, more efficient and gives you higher level control. Using for_each in conjunction with recursion is a very flexible way to construct "tree walkers" that can descend complex structures to operate on nested data.

Returned Value Capabilities

Unlike looping mechanisms in lower level languages, Water's for_each always returns a value. The result can be the value of the last iteration, or an accumulation of values from all or just some iterations. for_each in combination with helper methods lets you sum values, find the maximum value, return a list of all or a particular filtered set of values and many other capabilities. See the description of the combiner parameter below.

A Simple Example

There are a lot of features in for_each as the length of this documentation indicates. But you need not read it all to start using for_each . Here's an example of a simple call that you can generalize to perform many of the looping tasks you'll need in normal programming.
<set my_colors=<vector "red" "green" "blue"/> />
my_colors.<for_each combiner=insert> 
    key.<join " is " value/>
   </for_each>
<vector "0 is red" "1 is green" "2 is blue"/>
Each time around the loop, key.<join " is " value/> is executed with key bound to 0, 1, and 2 successively and value bound to "red" , "green" , and "blue" successively. The results of executing key.<join " is " value/> are "0 is red" , "1 is green" , "2 is blue" successively. combiner=insert tells for_each to insert each iteration result into a vector. It is called combiner since it is actually combining the new iteration result with the previous ones. That vector is returned by for_each . It is equal to <vector "0 is red" "1 is green" "2 is blue"/> The combiner method defaults to the method return_first_arg which will cause the value of the last iteration to be returned. Here we wanted a vector of all iteration results to be returned which is what combiner=insert gives us.

a wob
Parameter keyDefault valueType
_subjectopt
The possible items looped over are controlled by the subject of the call to for_each.

a wob
_subject=vector
The most common object to loop over is a vector. Each time around the loop, the local variable 'key' is bound to the index of the vector element being looped over and the local variable 'value' is bound to the value of the element. Looping stops when all the elements of the vector have been looped through. See the "Simple Example" above for looping through the fields of a vector.
a wob
_subject=object
You can loop over all or a subset of the fields within any object. If a non-vector, non-integer object is the subject in a call to for_each, it is treated as a 'supervector' and all its non-negative consecutive integer fields are looped over unless you have a non-default value for 'include'. include provides a way for you to select which fields of the object to loop over.
<color red=180 green=10 blue=150/>.<for_each include=regular_key combiner=insert>
         key.<join " is " value/>
      </for_each>
<vector "red is 180" "green is 10" "blue is 150"/>
See below for details on 'include'.
a wob
_subject=integer
If the subject of a call to for_each executes to a non-negative integer, for_each will loop that number of times. The key and value are bound to the current integer being looped over, which is between 0 inclusive and the given integer exclusive.
3.<for_each combiner=insert>
        key.<join " is " value/>
      </for_each>
<vector "0 is 0" "1 is 1" "2 is 2"/>
a wob
_subject=number.double
If the subject of a call to for_each executes to a double, it will be rounded to an integer and behave as if that integer were the subject. This is primarily useful when a math computation yields something like 3.000001 as often happens with floating point computation.
2.9.<for_each combiner=insert>
        key.<join " is " value/>
      </for_each>
<vector "0 is 0" "1 is 1" "2 is 2"/>
a wob
_subject=optional
If a call to for_each is given no subject, it will error unless the 'forever' argument is true. ('forever' defaults to false.) When there is no subject and forever=true, key and value are not bound during execution of the content and looping continues until a call to return is reached. You must have a call to break or return in the content or else you'll have an infinite loop and your code will never stop executing.
<for_each forever=true>
        <set rand_val=10.<random/>/>
        <if> rand_val.<is 5/> <return "we are finished" from="for_each"/> 
             else rand_val
       </if>
     </for_each>
"we are finished"
The 'from' parameter tells what call you are returning from. Above we specify 'for_each' so the result of the call to for_each will be the string "we are finished". We could have chosen to return from the method that our for_each call was in, or some method that called it, etc, on up the stack. See below for documentation on the parameter 'forever', and the method 'return'. 'return' is documented under 'content'.

a wob
Parameter keyDefault valueType
includevector_keyvar
include only certain fields to loop over
When the subject of the call to for_each is an integer, for_each loops over the integers less than it. When there is no subject, for_each loops until it executes a call to return. Otherwise, it loops over the fields of the subject. By default the object being looped over is treated as a vector and only its integer fields are looped over starting with field 0 (zero). Note that a non-vector can have integer fields too and be considered a "supervector". such as <thing 0="zero" 1="one" weight=99/>

<thing 0="zero" 1="one" weight=99/>.
         <for_each combiner=insert> key </for_each>
<vector 0 1/>
Here "weight" is ignored and just 0 and 1 are looped over. Since the result of executing the content of for_each during each iteration is simply the value of the 'key' being looped over, and combiner=insert tells for_each to collect all the iteration results, we get a vector of 0 and 1. The "include" argument is usually a method that determines exactly which fields to select for processing. Water provides several methods that were made expressly for the value of include:
a wob
include=vector_key
(the default) Selects the integer-named fields in a vector. This method is handled specially by for_each for performance and to process only those integer fields from 0 to just under the length of the subject.
a wob
include=string_key
Selects all the keys that are strings but are not system_key or meta_key named fields.
a wob
include=regular_key
Selects fields that are either vector_ley or string_key named fields.
a wob
include=system_key
Selects keys that are strings that don't start with underscore. Used to select fields such as "_parent". Rarely used.
a wob
include=meta_key
Selects only field names that are strings that contain an _f_ substring.
a wob
include=non_system_key
Selects all non_system field keys, thus it passes string_keys, vector_keys, meta_keys, and negative integer fields.
a wob
include=return_true
Selects all fields.
Our example above has include default to vector_key. If we wanted to include "weight" we'd use include=regular_key like so:
<thing 0="zero" 1="one" weight=99/>.<for_each include=regular_key combiner=insert> 
              key 
      </for_each>
<vector "weight" 0 1/>
Here's how to exclude the integer keys, system keys and anything that's not a string key.
<thing 0="zero" 1="one" weight=99/>.<for_each include=string_key combiner=insert> 
              key 
      </for_each>
<vector "weight"/>
You can write your own methods to include other fields than the above methods allow. The method is called with each key as _subject If the method returns false, the field will not be processed, otherwise it will be.
<method is_string_starting_with_a>
   string.<is_type_for _subject/>.<and 
       _subject.<length/>.<more 0/>
       _subject.0.<is <char "a"/>/>/>
</method>
<thing apple="red" apricot="orange" banana="yellow"/>.
      <for_each include=is_string_starting_with_a combiner=insert>
         key
      </for_each>.<sort/>
<vector "apple" "apricot"/>
Note that the order of processing non-vector keys is undefined so when dealing with string keys or any unusually keys, be prepared to handle them in any order. The above might return <vector "apple" "apricot"/> instead of <vector "apricot" "apple"/> If you want to process the fields of an object in a sorted order, here's one way:
<set fruits=<thing apple="red" apricot="orange" banana="yellow"/>>
  fruits.<keys/>.<sort/>.<for_each combiner=insert> value </for_each>
</set>
<vector "apple" "apricot" "banana"/>
Note above that the "value" in the content of the for_each call is really a key from the fruits object. To turn that key back into the real value of a field from the fruits object:
<set fruits=<thing apple="red" apricot="orange" banana="yellow"/>>
  fruits.<keys/>.<sort/>.<for_each combiner=insert> fruits.<get value/> </for_each>
</set>
<vector "red" "orange" "yellow"/>
Above we have effectively sorted the colors by the keys they are associated with.
a wob
include=vector
The value of include can also be a vector listing the fields to include. Only those fields that are in the include vector will be "looped over". If any fields are in the include vector but NOT in the subject, then they are simply ignored. Furthermore the order of the looping will be the order of the items in the include vector.
<vector "zero" "one" "two"/>.<for_each include=<vector 1 0 99/> combiner=insert>
                                 value
                               </for_each>
<vector "one" "zero"/>
a wob
include=type
If the value of "include" is NOT a method or a vector, then it is considered to be a type. If the field key being tested is of that type, then it will be looped over, otherwise it will be skipped. Below only the fields 2.5 and 3.5 are chosen, and since our combiner is plus, the result is 6.0.
<thing 1="one" 2.5="twopointfive" 3="three" 3.5="threepointfive"/>.
   <for_each include=number.double combiner=plus>
      key
   </for_each>
6.0
<vector "zero" "one" "two" "three"/>.<for_each include=integer.even combiner=insert>
                                       value
                                    </for_each>
<vector "zero" "two"/>

a wob
Parameter keyDefault valueType
excludenull
The exclude parameter, like the include parameter, can take a method, a vector, or a type. If a field name passed the include test, then it is tested against the exclude parameter. If the field name matches what is to be excluded, then the field is skipped. Think of exclude as having veto power over a key that passes the include test. The default value for exclude is the method returns_true meaning nothing is excluded.

<vector 100 101 102 103 104/>.
  <for_each combiner=insert exclude=<vector 1 3/>> key </>
<vector 0 2 4/>
Below is achieves the same result as an example in the "include" section that uses include=number.double Here we are including all the keys except the "_parent" key yielding 1, 2.5, 3, and 3.5, then we are excluding from that set the integer keys until we are left with just 2.5 and 3.5, which are summed to get 6.0.
<thing 1="one" 2.5="twopointfive" 3="three" 3.5="threepointfive"/>.
   <for_each include=non_system_key exclude=integer combiner=plus>
      key
   </for_each>
6.0

a wob
Parameter keyDefault valueType
foreverfalseboolean
If forever is true, that tells for_each to continue looping after it would normally be done. One way to use it is to make multiple passes over fields in an object or to loop through the integers less than the subject integer multiple times. First here's an example with forever=false, which is the default value.

<set mycount=0/>
2.<for_each combiner=insert forever=false> 
    <if> mycount.<is 5/> <break for_each_result/>
        else <do <set mycount=mycount.<plus 1/> /> value/>
   </if>
  </for_each>
<vector 0 1/>
We loop through 0, and 1, then stop because the subject of 2 sets the limit. Next here's the same example with forever=true:
<set mycount=0/>
2.<for_each combiner=insert forever=true> 
  <if> mycount.<is 5/> <break/>
       else <do <set mycount=mycount.<plus 1/> /> value/>
  </if>
</for_each>
<vector 0 1 0 1 0/>
The execution loops through 0 and 1, but because forever=true it doesn't stop, It does the same loop again and even gets into a third time before stopping due to the call to break. If we have no subject to our call to for_each, it will error if forever=false. But if forever=true, it loops until a call to break.
<set mycount=0/>
<for_each combiner=insert forever=true> 
   <if> mycount.<is 5/> <break/>
       else <do <set mycount=mycount.<plus 1/> /> mycount/>
   </if>
 </for_each>
<vector 1 2 3 4 5/>
Note that in the above example with no subject, key and value are not bound when the content of the for_each is executed so we can't reference them.

a wob
Parameter keyDefault valueType
contentfalse
The content of for_each is executed once for each iteration of the loop. During the execution:

Other local variables that are bound before the call to for_each, but in the same lexical scope (such as the same method body) will still be bound each time the body of the for_each is executed. _subject is still bound to _subject of the method call of the method that the for_each call is in.
a wob
content=skip
If the last expression of an iteration is the variable "skip", then no value is "accumulated" into for_each_result for this iteration. skip is useful when you want to filter-out certain values from the returned result. Below we filter out all instances of 4 from the vector.
<vector 2 4 6 4 8 4/>.<for_each combiner=insert> 
     <if> value.<is 4/> skip 
          else          value
     </if>
</for_each>
<vector 2 6 8/>

How To Stop Looping

There are several ways to stop looping. It is important to understand them all. The normal way is to just let for_each go through all of the elements that it is designated to loop over based on the subject and the include and exclude attributes. That is documented above under the documentation about the subject, include and exclude. But sometimes you discover, dynamically that you want to end the loop. If you have no subject and forever=true, you MUST explicitly end the loop.
a wob
content=break
The primary way of doing this is to call <break/> If you call break with no arguments or an argument of skip, i.e. <break skip/> , then iteration will stop and for_each will return the value of what for_each_result was before the call to break.
5.<for_each combiner=insert> <if> value.<is 3/> <break/>
                  else value
             </if>
</for_each>
<vector 0 1 2/>
If you call break with an argument, that argument will supply the value of the current iteration and it will be combined with the combiner into for_each_result and the new value of for_each_result will be returned.
5.<for_each combiner=insert> <if> value.<is 3/> <break 99/>
                  else value
             </if>
</for_each>
<vector 0 1 2 99/>
Use <break/> when you have done one iteration too many and want to end the loop with what has already been computed in for_each_result. use <break "some val"/> when you know you've reached the last iteration and want to add one last value to for_each_result before returning for_each_result.
a wob
content=return
Most of the time, <break/> is the best way to stop looping for_each early. But when you want to return a specific value that has nothing to do with for_each_return, or you want to return from more than the current_for_each call, calling return can be very handy. A call to return can appear anywhere in Water code, but it is particularly useful in the content of a call to for_each for exiting the loop early.
Example: Find the first number greater than 4
<vector 2 4 6 8/>.<for_each> 
     <if> value.<more 4/> <return value from="for_each"/> </if>
</for_each>
6
If you have nested calls to for_each, a return from the inner one will leave the code still executing the outer one. To have a call to return exit from the outer one, have the from value not be "for_each", but rather the name of the method that contains the outer for_each call.
<method find_5th_leaf vec=req>
  <set mycount=0/>
  vec.<for_each>   
    <if> 
        vector.<is_type_for value/>
            value.<for_each>
               <set mycount=mycount.<plus 1/>/>
               <if> mycount.<is 5/> <return value from="find_5th_leaf"/> </if>
            </for_each>
         mycount.<is 5/> 
            <return value from="find_5th_leaf"/>
         else <set mycount=mycount.<plus 1/>/>
    </if>
  </for_each>
</method>
<find_5th_leaf <vector 0 10 <vector 20 30 40 50/> 60/>/>
40
Below is a difference approach to returning from the inner level of a nested call to for_each. Instead of returning from the surrounding method, we set the value to ultimately return to a local variable (in this case the_result). We are now free to use the value returned by 'return' to be a control value (in this case, "done"). This string has no special significance, we just check for it in our outer for_each call and if we find it, return from that outer for_each call as well.
<method find_5th_elt vec=req>
  <set the_result=null/>
  <set mycount=0/>
  vec.<for_each>
    <if> vector.<is_type_for value/>
            <if> value.<for_each>
                         <set mycount=mycount.<plus 1/>/>
                         <if> mycount.<is 5/> 
                            <do <set the_result=value/>
                                <return "done" from="for_each"/>
                            /> 
                         </if>
                      </for_each>.<is "done"/>
                 <return from="for_each"/>
             </if>
        mycount.<is 5/> 
           <do <set the_result=value/>
                <return from="for_each"/>
           />
        else <set mycount=mycount.<plus 1/>/> 
    </if>
  </for_each>
  the_result
</method>
<find_5th_elt <vector 0 10 <vector 20 30 40 50/> 60/>/>
40
Note that find_5th_elt is only good for working on data of depth 2. See below on walking trees for more general algorithms that can descend arbitrarily deep into nested vectors.

infinite loop

If you do accidentally create an infinite loop and you're in the Steam development environment, just click on the "Cancel" button to stop looping.

a wob
Parameter keyDefault valueType
for_each_resultopt
holds the value returned by for_each
Looping constructs in many languages return no values. Java's and C's for loops are an example. In Water there are no "void" methods. Every call returns a value. Not only does this make the language more uniform, it makes it more useful as well. You can, of course, choose to ignore the returned values, but returned values from Water's control methods such as if and for_each can save you a lot of work. By default, for_each returns the value of executing the content of the for_each call the very last time it is executed.

5.<for_each> value </for_each>
4
You can change what for_each returns by giving the combiner argument a method. Each time through the loop this method will be called with the previous result, stored in the for_each_result variable, as the subject and the result of the current iteration as the first argument. The result of that call is stored back into for_each_result. Effectively here's what happens at the end of each iteration: <set for_each_result=for_each_result.<<do combiner/> current_iteration_result/>/> The value of for_each_result is returned from the call to for_each after the last iteration is executed and the value of for_each_result is updated as a result of it. But this begs the question, how do we get the initial value of for_each_result? You can supply it with the for_each_result argument.
<vector 5 7/>.<for_each combiner=insert for_each_result=<vector 1 3/>>
              value
    </for_each>
<vector 1 3 5 7/>
for_each_result is also useful to supply a result for a call to for_each that has no iterations.
0.<for_each for_each_result=99> value </for_each>
99
We would never write a call to for_each with an explicit subject of zero since that is guaranteed to have no iterations. But if the number of times to iterate is computed by our program, or some combination of the include and exclude arguments just so happen to exclude all iterations, initializing for_each_result can come in very handy. For many of the most useful methods that we will want to use for the value of the combiner argument, there is a natural initial value for for_each_result. For example, when we are using combiner=insert, the natural for_each_result is an empty vector. If we are using plus to add up the value of each iteration, the natural initial value for for_each_result is 0. We can supply these natural values explicitly and that's fine, but there is an easier way. for_each_result has a "smart default" that depends on the combiner method. At the end of each iteration, the combiner method is called (unless the iteration result is skip with for_each_result as the subject and the iteration result as the first arg. On the first iteration, for_each_result, unless it was explicictly passed in, will be optional. All of the standard methods used as combiners return something sensible when called with an optional subject and a first arg. return_first_arg, plus, times, minimum, maximum, and, or, and join all return their first arg. append returns a copy of its first arg. insert returns a vector with one element, the first arg. Once we're done with the first iteration, for_each_result will have a real value and it will be used as the subject to successive calls to the combiner method. However, if no iterations happen, then the combiner is called with no subject and no arguments and the result of that call is returned by for_each. Again, all of the usual methods to use as combiners return sensible results:

a wob
Parameter keyDefault valueType
combinerreturn_first_argvar
A method that combines interation results into for_each_result
The methods used as values for for_each's combiner argument can be any Water method. Many of the most useful are Water methods that you'll use outside of the context for for_each as well. One of the most common methods to use as a value of combiner is "insert". Here's a normal call to insert:

<vector 3 5/>.<insert 7/>
<vector 3 5 7/>
Using combiner=insert, you can accumulate the value of each iteration into a vector and return that vector from the call to for_each like so:
<vector 3 5 7/>.<for_each combiner=insert> value.<plus 1/> </for_each>
<vector 4 6 8/>
At the end of each iteration, insert is being called with the value of the iteration ( 4, 6 and 8 successively) and being inserted into the vector that is the value of for_each_result. Using combiner=insert is useful as a debugging tool since it can show you the result of each iteration. More generally, think of insert as a way to copy elements of a structure, or copy modified version of elements as in our example above where we are essentially copying the elements of the vector but adding one to each just before we insert them into the new vector. You needn't copy all of the elements of the subject, you can select which ones using the include argument or explicitly exclude certain ones using the exclude argument. (See documentation above.) An additional way to filter out undesired values is to have the last expression executed in an iteration be the variable skip.
<vector 4 11 5 12 6 13/>.<for_each combiner=insert>
      <if> value.<more 10/> value
           else             skip
      </if>
   </for_each>
<vector 11 12 13/>
You can use combiner to sum up the iteration values, find the minimum or maximum values and an unlimited number of other possibilities. It is called combiner because they all, in some sense, combine the current iteration result with the existing value of for_each_result to form a new value for for_each_result. Many more examples of using combiner are below.

Writing your own combiner method

If you are writing your own combiner method, either make sure that it can be called with no subject and no first argument as well as no subject and a first arg, or always supply a for_each_result when you use the method in a call to for_each.
<method double_then_add _subject=0 arg=0> 
           arg.<times 2/>.<plus _subject/>
      </method>
<double_then_add/>
0
<vector 3 10/>.<for_each combiner=double_then_add> value </for_each>
26
In the above example, first <double_then_add/> is called to yield 0 which is bound to for_each_result then for_each_result.<double_then_add 3/> is called to yield 0 + (3 * 2) equals 6 which is bound to for_each_result. then for_each_result.<double_then_add 10/> is called to yield 6 + (10 * 2) equals 26 which is returned. We could have achieved the same functionality with:
<vector 3 10/>.<for_each 
   combiner=<method null arg=req> arg.<times 2/>.<plus _subject/></>
   for_each_result=0
      >
  value
</for_each>
26
Note that <method arg=required> "..." </> makes an unnamed method. Had we done <method arg> "..." </> arg would have been interpreted as the name of the method which would take no arguments. We could have also defined it <method foo arg=req> "..." </> but since we are intending it to just be called from this one place, we might not want to redefine some other method previously named foo
a wob
combiner=return_first_arg
The default value for combiner is the method return_first_arg. All this method does is return its first argument. If there is no subject and no first argument, it returns null. Using combiner=return_first_arg causes for_each to return the value of the last iteration whose value was not skip. In the below example, combiner defaults to return_first_arg. Our content code is called 5 times, but only for the first three do we call return_first_arg to accumulate the result into for_each_result because for the iterations with values 12 and 15, the result is skip.
<vector 3 6 9 12 15/>.<for_each>
         <if> value.<more 10/> skip
              else             value
         </if>
   </for_each>
9
<return_first_arg/> returns null which is the smart default for for_each_result.
a wob
combiner=insert
combiner=insert collects the value of each iteration into one vector and returns it. <insert/> is <vector/> which is the smart default for for_each_result. The documentation for combiner has example calls to for_each using combiner=insert. Use insert in conjunction with skip to filter values out of the resulting vector.
a wob
combiner=append
append is similar to insert except that you give it a vector of values to append to the subject. Using combiner=append lets you add a variable number of elements to for_each_result for each iteration. Note that using combiner=append with an iteration value of the empty vector is like using combiner=insert with an iteration value of skip. <append/> returns <vector/> which is the smart default for for_each_result.
<vector 3 6 9 12 15/>.<for_each combiner=append>
          <if> value.<less 10/> <vector key value/>
               else <vector/>
          </if>
   </for_each>
<vector 0 3 1 6 2 9/>
Note that append always returns a new vector so even if you call for_each with combiner=append and for_each_result=foo where foo is a vector, foo will not be modified by the call to for_each but will return a vector whose first items are the same as foo's.
a wob
combiner=plus
combiner=plus lets you compute the sum of the results of each iteration.
<plus/>0
which is the smart default for for_each_result. The below example performs 0 + 0 + 1 + 2 + 3 and returns 6.
4.<for_each combiner=plus> value </for_each>
6
a wob
combiner=times
combiner=times lets you compute the product of the results of each iteration.
<times/>1
which is the smart default for for_each_result. The below example performs 1 * 2 * 3 * 4 and returns 24.
<vector 2 3 4/>.<for_each combiner=times> value </for_each>
24
a wob
combiner=minimum
combiner=minimum lets you find the smallest of the results of each iteration.
<minimum/>integer.max_value
which is the smart default for for_each_result.
<vector 5 3 99 7/>.<for_each combiner=minimum> value </for_each>
3
a wob
combiner=maximum
combiner=maximum lets you find the largest of the results of each iteration.
<maximum/>integer.min_value
which is the smart default for for_each_result.
<vector 5 3 99 7/>.<for_each combiner=maximum> value </for_each>
99
a wob
combiner=and
combiner=and lets you determine if all the iteration results are not false.
<and/>true
which is the smart default for for_each_result. and considers any non-false value to be "true". If all of the values are non-false, it returns the last argument to 'and', else it returns false. So
2.<and 3/>3
...and result is not true. This let's 'and' return a potentially more useful result than true. Since the test clauses of 'if' work off of false and non-false, and works well with 'if' as well as methods that require more than a boolean.
<vector true true false true/>.<for_each combiner=and> value </for_each>
false
<vector true true thing 27/>.<for_each combiner=and> value </for_each>
27
a wob
combiner=or
combiner=or lets you determine if at least one of the iteration results is not false.
<or/>false
which is the smart default for for_each_result. 'or' considers any non-false value to be "true". or returns the first non-false argument or false. So
2.<or false/>2
...result is not true.
<vector true true false true/>.<for_each combiner=or> value </for_each>
true
<vector false false false/>.<for_each combiner=or> value </for_each>
false
<vector false false 34/>.<for_each combiner=or> value </for_each>
34
a wob
combiner=join
combiner=join lets for_each return one big string containing a concatenation of all the strings.
<vector "hey" "you"/>.<for_each combiner=join> value</for_each>
"heyyou"
Calling join with no arugments and no subject:
<join/>""
gives us the smart default for for_each_result Note that when using combiner=join returning a value of skip from an iteration is the same as returning a value of "". join calls to_string on the values it is about to join so in order to get a string of html we must call to_htm on the value first.
<vector 3 <b>hi</b> "you"/>.<for_each combiner=join> value.<to_htm/></>
"3<b>hi</b>you"
Note that when using combiner=join returning a value of skip from an iteration is the same as returning a value of ""

for_each Caveats

When you are looping over the fields of the subject in a call to for_each, it is recommended that you not delete or add fields to that subject in the content of the for_each. For non-vector_keys, you can't be sure of the order that looping will occur so be careful if you want to modify the values of fields you're looping over as that might have results that you don't expect.

Fibonacci Examples

Computing a Fibonacci series is one of those standard algorithms used to demonstrate how a programming language works. The Fibonacci series is a series of integers whose first integer is 0, second integer is 1, and each integer thereafter is the sum of the previous two integers in the series. Below we have a number of examples showing different ways of using for_each to compute the Fibonacci series of length 10. For our first example we use the length of for_each_result as our "counter" that tells us what number of the sequence we're on. This enables us to special case the first, second and last iterations. Since we are calling for_each with no subject and forever=true, we must have a call to return. It is executed on the last iteration. The result is combined using 'insert' into for_each_result to produce the vector of integers we desire.
<for_each combiner=insert forever=true>
  <set len=for_each_result.<length/>/>
  <if> len.<is 0/> 0
       len.<is 1/> 1
       len.<is 10 /> <return for_each_result from="for_each"/>
       else <plus for_each_result.<get len.<minus 1/>/> 
                  for_each_result.<get len.<minus 2/>/>/>    
  </if>
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
Next we supply an for_each_result of <vector 0 1 /> to handle our first and second "special cases". We will only have 8 iterations in this case making our code faster as well as smaller.
<for_each combiner=insert forever=true for_each_result=<vector 0 1 /> >
  <set len=for_each_result.<length/>/>
  <if> len.<less 10 />
      <plus for_each_result.<get len.<minus 1 /> /> 
            for_each_result.<get len.<minus 2 /> /> />
  else
     <return for_each_result from="for_each" />
  </if>
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
Next we have a much different algorithm. We are using the length of the series we want to compute as the subject, i.e. 10. Upon the first iteration, value is bound to 0 and on the second it is bound to 1, so we can use the value of 'value' to supply our first and second result elements. The trick of value.<less 2/> saves us one 'if' clause over the first example. We save another if clause, i.e. the check for "done" by having for_each do that for us automatically by virtue of the fact that we have an integer as the subject of our call to for_each. Note that we are replacing for_each_result.<get len.<minus 1/> /> with for_each_result.<last 1/> and for_each_result.<get len.<minus 2/> /> with for_each_result.<last 2/> This avoids us having to calculate the length of for_each_result altogether. Note that the first argument to last defaults to 1 so we could have said <last/> instead of <last 1/> but making it explicit reads well.
10.<for_each combiner=insert>
  <if> value.<less 2/> 
         value
       else 
         <plus for_each_result.<last 0/> 
               for_each_result.<last 1/> />
  </if>
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
Below we combine the above for_each example with using for_each_result. Since we have already supplied the first two result elements, we need to be sure to 'skip' adding them onto for_each_result.
10.<for_each combiner=insert for_each_result=<vector 0 1/>>
  <if> value.<less 2/> 
            skip      
         else 
         <plus for_each_result.<last 0/> 
               for_each_result.<last 1/> />
  </if>
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
The inefficiency with the above example is that we needlessly execute the first two iterations and just 'skip' what they could have computed. Because we're using last, and our special-casing of the first two items is handled via for_each_result=<vector 0 1/> and using an integer for the subject automatically provides the ending condition, we don't need to know what number of the series we are computing within each iteration. Thus we are just using the integer subject to declare the number of iterations, nothing more. All of the special-casing is handled by the built-in machinery of for_each. However, we need two less iterations than the length of our result series so we just subtract 2 from the length of the series for a subject of 8 and end up with a very compact algorithm.
10.<minus 2/>.<for_each combiner=insert for_each_result=<vector 0 1/>>
         <plus for_each_result.<last 0/> 
               for_each_result.<last 1/> />
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
The second argument to 'last 'defaults to just returning one element, but had we wanted to return the last 3 elements of a vector we could say:
<vector 10 11 12 13 14 15/>.<last 2 "all"/>
<vector 13 14 15/>
Finally we're able to change our two-liner body into a one-liner by taking advantage of the 2nd argument to 'last'.
10.<minus 2/>.<for_each combiner=insert for_each_result=<vector 0 1/>>
         <plus _other_unkeyed=for_each_result.<last 1 "all"/>/> 
</for_each>
<vector 0 1 1 2 3 5 8 13 21 34/>
Along with Fibonacci you'll also see computing the factorial of a number as a classic Software 101 algorithm. This is the number times one less than the number times two less than the number ... all the way down to 1. Factorial of 3 is 3 times 2 times 1 equals 6. Factorial of 4 is 4 times 3 times 2 times 1 equals 24. Water's for_each makes this a one-liner.
Example: Factorial
3.<for_each combiner=times> value.<plus 1/> </>
6
Since value will be bound to 0, 1, and 2, we need to shift it up one to have the result of each iteration be 1, 2 and 3 successively. The order of our multiplies doesn't matter but we can't have a zero in there or our result will be zero. When using combiner=times, our initial result will default to <times/> which is 1. So in the above example we start with 1, multiply 1 by 1 to yield 1, then 1 by 2 to yield 2, then 2 by 3 to get 6.

Walk Tree Examples

for_each can be used to "walk trees", i.e. descend down into deeply nested data structures to test conditions, find particular values, modify values, or collect a variety of data to return. The examples below follow a particular pattern with is very flexible when dealing with nested data, especially when that data is fairly uniform. The data that we are walking in each example is a vector containing integers and other vectors containing integers, though this can certainly be generalized to walk objects and their fields using the 'include' argument to for_each. Each example defines a method that takes the nested vector to walk (which becomes the subject to the call to for_each) and sometimes the inital_result which becomes the value of for_each_result in the call to for_each. The body of the method consists of one call to for_each. The combiner argument in for_each changes depending on the example. The content of the call to for_each contains a call it 'if' which has two clauses. One clause test to see if the value being looped over is a leaf (in this case a number). If so the value is returned, sometimes after being modified. If the value is not a leaf we "recurse" by calling the method we have defined. The method is called with 'value' which will be a vector to do further processing on. This pattern sounds fairly restricted, yet with the flexibility of for_each and Water allows us to make a surprisingly large variety of computations. Our most basic example just copies the tree it is passed. This isn't too useful by itself, but you'll see how we build on this theme in later examples to derive lots of other results.
<method copy_tree vec=req>
    vec.<for_each combiner=insert>
       <if> value.<is_a number/> value      
            else  <copy_tree value/>
       </if>
    </for_each>
  </method>
<copy_tree <vector 2 <vector 1 <vector 5 6/>/> 4/>/>
<vector 2 <vector 1 <vector 5 6/>/> 4/>
Note that for this case, instead of value.<is_a number/> to test whether we have a leaf, we could have used value.<is_a vector/>.<not/> In general, though, what is a leaf and what isn't depends on how you want to treat your data. Below instead of making an exact copy, we're modifying each element in the new tree with: value.<times 10/>
Example: copy the tree but multiply each number by 10
<method copy_tree_times_10 vec=req>
      vec.<for_each combiner=insert>
         <if> value.<is_a number/> value.<times 10/>     
              else  <copy_tree_times_10 value/>
         </if>
     </for_each>
  </method>
<copy_tree_times_10 <vector 2 <vector 1 <vector 5 6/>/> 4/>/>
<vector 20 <vector 10 <vector 50 60/>/> 40/>
The below example is exactly the same as the original copy_tree, except that it has the non-default value for combiner of 'plus'. Since <plus/> is 0, for_each_result starts with 0. We add each number in the tree to it for a grand total of 10.
Example: sum all the items in the nested vectors
<method sum_tree vec=req >
      vec.<for_each combiner=plus>
         <if> value.<is_a number/> value        
              else  <sum_tree value/>
         </if>
     </for_each>
  </method>
<sum_tree <vector 2 <vector 1 <vector 1 1 1/>/> 4/>/>
10
The below example is the same as our plus example with 'plus' replaced by the method 'maximum'. Instead of adding the numbers together we simply find the highest one and return it.
Example: find the max item in the nested vectors
<method find_max_in_tree vec=req >
      vec.<for_each combiner=maximum>
         <if> value.<is_a number/> value        
              else  <find_max_in_tree value/>
         </if>
     </for_each>
  </method>
<find_max_in_tree <vector 2 <vector 1 <vector 5 6/>/> 4/>/>
6
Use the method 'minimum' to find the lowest value. If you want to find the average value, you can use plus to compute their sum, then use the count_leaves to find the number of numbers, then divide the sum by the count to make the average. That approach makes two passes over the tree. Another approach is to use 'flatten_tree' (see example below) to make a single vector of all the numbers, then sum them with plus and divide by the length of the flattened_vector like so:
<set flat_vec=<flattened_tree nested_vec/>>
 <plus rest=flat_vec/>.<divide flat_vec.<length/>/>
</set>
Below we are searching for a value that's "good enough". Once we find it we don't care if there are better values in the remainder of the tree so we want to exit our tree walk early to make the computation faster. We call 'return' with its 'from' argument equal to the name of the method to exit. We need to construct two methods so that we can return from the non-recursive outer method to get out of deeply nested calls to the inner method. If we had just one method, when we returned, we'd just get out of one nesting of the method and continue on without exiting all levels of the method.
Example: search_tree_and_return_early
<method find_first_number_over_4 vec=req >
   <find_first_number_over_4_aux vec/>
   false
</method>
<method find_first_number_over_4_aux vec=req >
    vec.<for_each>
       <if> value.<is_a number/>
            <if> value.<more 4/> <return value from="find_first_number_over_4"/> </if>     
            else  <find_first_number_over_4_aux value/>
       </if>
   </for_each>
</method>
<find_first_number_over_4 <vector 2 <vector 1 <vector 7 8/>/> 4/>/>
7
Below we want to count the leaves. Our trick is to use the same code for summing all the values, only instead of summing the actual values we just sum 1 for each leaf.
Example: count leaves in tree
<method count_leaves vec=req >
    vec.<for_each combiner=plus>
       <if> value.<is_a number/> 1       
            else  <count_leaves value/>
       </if>
   </for_each>
</method>
<count_leaves <vector 2 <vector 1 <vector 7 8/>/> 4/>/>
5
Below we are essentially doing a count but instead of always feeding 1 to plus we feed 0 to it when we want that value (any value 4 and under) to not count.
Example: count leaves in tree more than 4
<method count_leaves_more_than_4 vec=req >
    vec.<for_each combiner=plus>
       <if> value.<is_a number/> 
            <if> value.<more 4/> 1  else 0 </if>      
            else  <count_leaves_more_than_4 value/>
       </if>
   </for_each>
</method>
<count_leaves_more_than_4 <vector 2 <vector 1 <vector 7 8/> 9/> 4/>/>
3
When we want to operate on just the leaves of a tree, its often much easier to deal with a flat vector of objects than a tree nested to arbitrary depth. The example below shows how to create a flat vector out of a tree. This is rarely an end in itself, but rather a key stepping stone to other computations. The secrete to flatten_tree is to pass down the for_each_result created with the first call of flatten_tree into the recursive calls to flatten_tree. Just one vector is created for the value of for_each_result and added to by all levels.
Example: flatten a nested tree
<method flatten_tree vec=req for_each_result=<vector/>>
    vec.<for_each combiner=insert for_each_result=for_each_result>
       <if> value.<is_a number/> value      
            else  <do <flatten_tree value for_each_result/> skip/>
       </if>
   </for_each>
</method>
<flatten_tree <vector 2 <vector 1 <vector 5 6/>/> 4/>/>
<vector 2 1 5 6 4/>
Below we have another version of flatten that's the same as the above example except that we modify the value stored in the result vector with the code value.<times 10/>
Example: flatten and modify each leaf
<method flatten_tree_times_10 vec=req for_each_result=<vector/>>
    vec.<for_each combiner=insert for_each_result=for_each_result>
       <if> value.<is_a number/> value.<times 10/>     
            else  <do <flatten_tree_times_10 value for_each_result/> skip/>
       </if>
   </for_each>
</method>
<flatten_tree_times_10 <vector 2 <vector 1 <vector 5 6/>/> 4/>/>
<vector 20 10 50 60 40/>
Below we have another version of flatten that doesn't store all values in the returned vector, just those that are more than 4. We return 'skip' from those iterations that have a lower value to filter out those values.
Example: find numbers more than 4 in tree
<method numbers_more_than_4 vec=req for_each_result=<vector/>>
    vec.<for_each combiner=insert for_each_result=for_each_result>
       <if> value.<is_a number/> 
            <if> value.<more 4/> value else skip </if>    
            else <do <numbers_more_than_4 value for_each_result/> skip/>
       </if>
   </for_each>
</method>
<numbers_more_than_4 <vector 7 <vector 1 <vector 5 6/>/> 4/>/>
<vector 7 5 6/>