Operator Step (Iteration)

Increments the iterator of a For...Next loop

Syntax
   { Type | Class | Union } typename
      Declare Operator Step ()
      Declare Operator Step ( [ ByRef | ByVal ] stp As typename )
      ...
   End { Type | Class | Union }

Usage
   For iterator [ As typename ] = start_value To end_value [ Step 
   step_value ]
      [ ...statements... ]
   Next

Parameters
(including arguments)
   typename
      name of the Type, Class, or Union
   stp, step_value
      a typename object used as an incremental value
   iterator
      a typename object used as an iterator
   end_value
      a typename object used as a loop-terminating value
   start_value
      a typename object used to copy construct or assign to the iterator 
      initially

Description
   Operator For, Operator Next and Operator Step can be overloaded in 
   user-defined type definitions to allow objects of that type to be used 
   as iterators and step values in For...Next loops.
   As all non-static member procedures, they have passed a hidden This 
   parameter that allows to access by reference to the iterator object in 
   the code body of the 3 operators.

   Operator Step is called to increment the iterator object immediately 
   after all statements in the For...Next body are executed, if any.

   The first version of Operator Step is used if no step value is given in 
   the For...Next statement. If a step value is given, the second version 
   is used and is passed the step value to increment the iterator object.

   Advanced usage
      The above description seems to imply that the 3 arguments start_value
      , end_value, and step_value must be of the same type as the iterator 
      (this is the more obvious use), but it is not quite true:
         - The start_value, end_value, and step_value arguments can be of 
         any type (of different types among themselves and also of 
         different types from the one of the iterator).
         - The only constraint is that the iterator could be constructed 
         (in case of local iterator) or assigned (in case of global 
         iterator) from the start_value argument (because the iterator is 
         implicitly constructed or assigned under the hood).
         - Similarly the other parameters end_value, and step_value must be 
         able to be converted into objects of the same type as the iterator
         .

Example
   '' Example Type
   Type T
     '' value is set by the constructor
     value As Double
     Declare Constructor( ByVal x As Double = 0 )

     Declare Operator For( ByRef stp As T )
     Declare Operator Step( ByRef stp As T )
     Declare Operator Next( ByRef cond As T, ByRef stp As T ) As Integer
   End Type

   Constructor T ( ByVal x As Double )
     Print "T iterator constructed with value " & x
     value = x
   End Constructor

   Operator T.for( ByRef stp As T )
   End Operator

   Operator T.step( ByRef stp As T )
     Print " incremented by " & stp.value & " in step."
     value += stp.value
   End Operator

   Operator T.next( ByRef cond As T, ByRef stp As T ) As Integer
     '' iterator's moving from a high value to a low value (step >= 0)
     If( stp.value < 0 ) Then
      Return( value >= cond.value )
     Else
     '' iterator's moving from a low value to a high value (step < 0)
      Return( value <= cond.value )
     End If
   End Operator

   '' Example Usage. It looks like we are working with numbers, but the iterators
   '' have overloaded constructors. The 10, 1, and -1 are all of type T.
   For i As T = 10 To 1 Step -1
     Print i.value;
   Next i
      

   A more practical example demonstrating file iteration based on 
   cha0s' file iteration class:
   '' a class which iterates through files
   Type FileIter
      As String pathName, fileName
      Declare Constructor( ByRef pathName As String )

      Declare Operator For()
      Declare Operator Step()
      Declare Operator Next( ByRef endCond As FileIter) As Integer
   End Type

   Constructor FileIter( ByRef pathName As String )   
      this.pathName = pathName
   End Constructor

   Operator FileIter.for( )   
      fileName = Dir(pathName & "/*.*")   
   End Operator

   Operator FileIter.step( )   
      fileName = Dir("")
   End Operator

   Operator FileIter.next( ByRef endCond As FileIter ) As Integer
      Return(fileName <> endCond.pathName)   
      '' the c'tor sets the path name and so we check against that
   End Operator

   '' example code
   '' change it to any directory
   For i As FileIter = "./" To ""
      Print i.fileName
   Next
      

   Another example working with strings:
   Type CharIterator
      '' used to build a step var
      Declare Constructor( ByVal r As ZString Ptr )
      
      '' implicit step versions
      Declare Operator For ( )
      Declare Operator Step( )
      Declare Operator Next( ByRef end_cond As CharIterator ) As Integer
      
      '' explicit step versions
      Declare Operator For ( ByRef step_var As CharIterator )
      Declare Operator Step( ByRef step_var As CharIterator )
      Declare Operator Next( ByRef end_cond As CharIterator, ByRef step_var As CharIterator ) As Integer
      
      '' give the current "value"    
      Declare Operator Cast( ) As String
      
      Private:   
         '' data
         value As String
         
         '' This member isn't necessary - we could use
         '' the step variable on each iteration - 
         '' but we choose this method, since we have
         '' to compare strings otherwise. See below.
         is_up As Integer
   End Type

   Constructor CharIterator( ByVal r As ZString Ptr )
      value = *r
   End Constructor

   Operator CharIterator.cast( ) As String
      Operator = value
   End Operator

   '' implicit step versions
   '' 
   '' In this example, we interpret implicit step
   '' to always mean 'up'
   Operator CharIterator.for( )
      Print "implicit step"
   End Operator

   Operator CharIterator.step( )
      value[0] += 1
   End Operator 

   Operator CharIterator.next( ByRef end_cond As CharIterator ) As Integer
      Return this.value <= end_cond.value
   End Operator

   '' explicit step versions
   '' 
   '' In this example, we calculate the direction
   '' at FOR, but since the step var is passed to
   '' each operator, we have the choice to also calculate
   '' it "on-the-fly". For strings such as this, repeated comparison
   '' may penalize, but if you're working with simpler types,
   '' then you may prefer to avoid the overhead of 
   '' an 'is_up' variable.
   Operator CharIterator.for( ByRef step_var As CharIterator )
      Print "explicit step"
      is_up = (step_var.value = "up")
   End Operator

   Operator CharIterator.step( ByRef step_var As CharIterator )
      If( is_up ) Then
         value[0] += 1
      Else
         value[0] -= 1
      End If
   End Operator 

   Operator CharIterator.next( ByRef end_cond As CharIterator, ByRef step_var As CharIterator ) As Integer
      If( this.is_up ) Then
         Return this.value <= end_cond.value
      Else
         Return this.value >= end_cond.value
      End If
   End Operator

   For i As CharIterator = "a" To "z"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "a" To "z" Step "up"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "z" To "a" Step "down"
      Print i; " ";
   Next
   Print "done"

   For i As CharIterator = "z" To "a" Step "up"
      Print i; " ";
   Next
   Print "done"
      

   Iterating with fractions:
   Type fraction
      '' Used to build a step var
      Declare Constructor( ByVal n As Integer, ByVal d As Integer )

      '' Implicit step versions
      Declare Operator For ( )
      Declare Operator Step( )
      Declare Operator Next( ByRef end_cond As fraction ) As Integer

      '' Explicit step versions
      Declare Operator For ( ByRef step_var As fraction )
      Declare Operator Step( ByRef step_var As fraction )
      Declare Operator Next( ByRef end_cond As fraction, ByRef step_var As fraction ) As Integer

      '' Give the current "value"    
      Declare Operator Cast( ) As Double
      Declare Operator Cast( ) As String

      Private:
         As Integer num, den
   End Type

   Constructor fraction( ByVal n As Integer, ByVal d As Integer )
      This.num = n : This.den = d
   End Constructor

   Operator fraction.Cast( ) As Double
      Operator = num / den
   End Operator

   Operator fraction.Cast( ) As String
      Operator = num & "/" & den
   End Operator

   '' Some fraction functions
   Function gcd( ByVal n As Integer, ByVal m As Integer ) As Integer
      Dim As Integer t
         While m <> 0
            t = m
            m = n Mod m
            n = t
         Wend
      Return n
   End Function

   Function lcd( ByVal n As Integer, ByVal m As Integer ) As Integer
      Return (n * m) / gcd( n, m )
   End Function

   ''
   '' Implicit step versions
   ''
   '' In this example, we interpret implicit step
   '' to mean 1
   ''
   Operator fraction.For( )
      Print "implicit step"
   End Operator

   Operator fraction.Step( )
      Dim As Integer lowest = lcd( This.den, 1 )
      Dim As Double mult_factor = This.den / lowest
      Dim As fraction step_temp = fraction( 1, 1 )
      
      This.num *= mult_factor
      This.den *= mult_factor
      
      step_temp.num *= lowest
      step_temp.den *= lowest
      
      This.num += step_temp.num
   End Operator

   Operator fraction.Next( ByRef end_cond As fraction ) As Integer
      Return This <= end_cond
   End Operator

   ''
   '' Explicit step versions
   ''
   Operator fraction.For( ByRef step_var As fraction )
      Print "explicit step"
   End Operator

   Operator fraction.Step( ByRef step_var As fraction )
      Dim As Integer lowest = lcd( This.den, step_var.den )
      Dim As Double mult_factor = This.den / lowest
      Dim As fraction step_temp = step_var

      This.num *= mult_factor
      This.den *= mult_factor

      mult_factor = step_temp.den / lowest

      step_temp.num *= mult_factor
      step_temp.den *= mult_factor

      This.num += step_temp.num
   End Operator

   Operator fraction.Next( ByRef end_cond As fraction, ByRef step_var As fraction ) As Integer
      If(( step_var.num < 0 ) Or ( step_var.den < 0 ) ) Then
         Return This >= end_cond
      Else
         Return This <= end_cond
      End If
   End Operator

   For i As fraction = fraction(1,1) To fraction(4,1)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(1,4) To fraction(1,1) Step fraction(1,4)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(4,4) To fraction(1,4) Step fraction(-1,4)
      Print i; " ";
   Next
   Print "done"

   For i As fraction = fraction(4,4) To fraction(1,4)
      Print i; " ";
   Next
   Print "done"
      

Dialect Differences
   * Only available in the -lang fb dialect.

See also
   * Operator For
   * Operator Next
   * For...Next

