Functions

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>
  

Custom Functions

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:

  • Its 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.


  • It calls operate() on its strategy, which can access the params array to get function parameters. Operate should update the result in the StrategyResult object.


  • It returns the value, by calling toValue() on the StrategyResult.