A datamixer function is a sequence iterator that gets its argument values from its
nested iterators. With each iteration, it gets the next value from each iterator, applies an operator to all the
values, and returns the operator's result wrapped in a Value object. For example, the add function
returns the sum of values as an IntValue.
A function tries to make a reasonable decision about the returned value's datatype. In general, it returns the
datatype with the greatest precision. For example, if two integer values are added, then the result is an integer.
If an integer and a double are added, then the result is a double. Datatype can be explicitly coerced by calling
setDataType(). If the datatypes of the nested iterators are not compatible, then an exception is
thrown. The following table lists datatype compatibility: (TBD).
This example adds two doubles, and generates 0.0, 0.2, 0.4, ...
<dm:doubles id="a" range="[0.0]0.1"/>
<dmf:add>
<iterator collection="a"/>
<iterator collection="a"/>
</dmf:add>
Functions can be nested. The next example generates a straight line with slope 3 and y-intercept -22, whose x values range from -5 to 4. This example shows that functions can use constant values as well as iterators. The result is:
-37 -34 -31 -28 -25 -22 -19 -16 -13 -10
<!-- f(x) = 3x - 22 for -5 <= x < 5 -->
<dmf:add datatype="int">
<dmf:multiply>
<dm:constants id="m" value="3"/>
<dm:ints id="x" range="[-5,5)"/>
</dmf:multiply>
<dm:constants id="b" value="-22"/>
</dmf:add>
The above example can be rewritten with the line function. In general, complex functions can be
customized for simplicity and to increase performance.
<dmf:line slope="3" intercept="-22">
<dm:ints id="x" range="[-5,5)"/>
</dmf:line>
A new function can be created by writing a class that derives from
FunctionStrategy.
When a FunctionIterator generates its next
value, it calls its strategy's operator() method. So in most cases, a custom function simply needs to
create a strategy that implements operator().
FunctionIterator takes these steps to generate a next value:
hasNext() method gets the next value from each iterator in the sequence iterator's list. If any
iterator returns false, hasNext() returns false. The values from each iterator are placed in an an
array named params.
operate() on its strategy, which can access the params array to get function
parameters. Operate should update the result in the StrategyResult object.
toValue() on the StrategyResult.