Page 1 of 1

Iterators Rate Topic: -----

#1 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2270
  • View blog
  • Posts: 9,496
  • Joined: 29-May 08

Posted 25 October 2013 - 07:14 PM

Iterators

Visual Studio VS2012 (VB11) introduced to the vb.net language the the ability to write Iterators.
With Iterator Function.

IEnumerable(Of T) Interface
To understand what an iterator is lets look at the return type an iterator has to be IEnumerable(Of ... ).

Interface IEnumerable(Of T)
  Public Function GetEnumerator() As IEnumerator(Of T) 
  Public Function GetEnumerator1() As IEnumerator 
End Interface



Not much to it basically it state that the object can be enumerated over. Think as enumerated as it produces a sequence of values. So this indicates that there needs to be a generic interface for producing that sequence.

IEnumerator(Of T)
Interface IEnumerator(Of T)
  Function MoveNext() As Boolean
  Sub Reset()
  ReadOnly Property Current As T
  ReadOnly Property Currect1 As Object
  Overridable Sub Dispose(disposing As Boolean)
End Interface


The core parts of the interface are the following method and property.
Interface IEnumerator(Of T)
  Function MoveNext() As Boolean
  ReadOnly Property Current As T
End Interface



MoveNext() As Boolean this return false if there isn't another value to produce, and returns true if there is. Important this also advance the value (current) to the next value.

Current As T this is the current value of the enumerator.

We tend to use in conjunction with IEnumerator the construct ForEach i In en
But this sort of get rewritten as a [i]While Loop[/il]
While en.MoveNext()
  Dim i = en.Current
  Console.WriteLine( i )
End While



Iterator

How does the Iterator Function help?
It helps by letting us write enumerators in a more convenient form and the compiler handles the task of converting into a enumerator. That enumerator can be very complex indeed, think VB.net's lets you use try ... catch inside it.

OK let implement an iterator, I'll pick to reimplement Enumerable.Take because it show what work the compiler does on your behalf.

 <Extension> Iterator Function Take(Of T)( source As IEnumerable(of T), count As Integer) As IEnumerable(Of T)
    Dim en = source.GetEnumerator
    While en.MoveNext AndAlso count>0
      Yield en.Current
      count-=1
    End While
  End Function



That's look relatively simple, doesn't it.

But remember that IEnumerator only work via essentially two methods MoveNext and Current.
So it needs to implemented via these two methods.

Public Class TakeEnumerator(Of T)
    Implements IEnumerator(Of T)
    Dim _Source As IEnumerator(Of T)
    Dim _Count As Integer = 0
    Dim _Limit As Integer
    Dim _Value As T

    Public Sub new (source As IEnumerable(OF T), Count As Integer)
      _Source = source.GetEnumerator 
      _Limit =Count
    End Sub
   Public ReadOnly Property Current As T Implements IEnumerator(Of T).Current
      Get
        Return _Value
      End Get
    End Property

    Public ReadOnly Property Current1 As Object Implements IEnumerator.Current
      Get
        Return Current 
      End Get
    End Property

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
      If (_Count < _Limit) OrElse (Not _Source.MoveNext) then Return False
      _Value =_Source.Current
      _Count +=1
      Return True  
    End Function

    Public Sub Reset() Implements IEnumerator.Reset
      _Source.Reset
      _Count = _Limit 
    End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean' To detect redundant calls

    ' IDisposable
    Protected     Overridable     Sub Dispose(disposing As Boolean)
      If Not Me.disposedValue Then
        If disposing Then
          ' TODO: dispose managed state (managed objects).
        End If

        ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
        ' TODO: set large fields to null.
      End If
      Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
      ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
      Dispose(True)
      GC.SuppressFinalize(Me)
    End Sub
#End Region

  End Class



Usage:
    Dim n=New TakeEnumerator(Of Integer)(ProduceRandomIntegerSequence(0,100),Count:= 5)
    ' The following is essential what ForEach does.
    While n.MoveNext
      Console.WriteLine(n.Current)
    End While



Which do you think is easier to write? The iterator version or the IEnumerator?
Spoiler





Examples

Iterator Function OneToHundred() As IEnumerable(Of Integer)
  For i=1 To 100
    Yield i
  Next
End Function



Spoiler


.To
<Extension>
Public Iterator Function To( f As Integer, t As Integer ) As IEnumerable(Of Integer)
  Dim s = If( f>t, -1,1)
  For i = f To t Step s
    Yield i
  Next
End Function




.Select
<Extension>
Public Iterator Function Select(Of T, TResult) ( Source As IEnumerable(Of T),
                                              Transform As Func(Of T,TResult) ) As IEnumerable(Of TResult)
  For Each Item In Source
    Yield Transform( Item )
  Next
End Function    



.Map
<Extension>
Public Iterator Function Map(Of T) ( Source As IEnumerable(Of T),
                                  Pred As Func(OF T, Boolean)) As IEnumerable(Of T)
  For Each item In Source
    If Pred( item ) Then Yield item
  Next
End Function



.Fold
<Extension> 
Function Fold(Of T, TResult)( Source As IEnumerable(Of T), seed As TResult, FoldFN As Func(Of TResult, T, TResult) ) As IEnumerable(OF TResult)
  Dim Result As TResult = Seed
  For Each Item In Source
    Result = FoldFn( Result, Item )
  Next
  Return Result
End Function



Do those iterators seem similar to existing methods?

Spoiler







Infinite Length Iterators
You have to be aware that it allows use write and Enumerator that has an infinite length
<Extension>
Iterator Function ProduceRandomIntegerSequence( Between As Integer, _And_ As Integer) As IEnumerable(Of Integer)
   While True
      Yield RNG.Next(Between, _And_ ) ' RNG is a System.Random
   End While
End Function



So be aware if you do something that goes through the sequence, for example .Select or .Where that it'll take forever. Or do something that'll us a finite subset of it first. eg .Take(10)

Examples of Mathematical Sequences Iterators
Public Iterator Function N0() As IEnumerable(Of Integer)
  For i = 0 To Integer.MaxValue
    Yield i
  Next
End Function

Public Function N1() As IEnumerable(Of Integer)
  Return N0.Skip(1)
End Function

Public Iterator Function Fib() As IEnumerable(of BigInteger)
  Dim q As New Queue(Of BigInteger)({BigInteger.Zero,BigInteger.One})
  While True
    q.Enqueue(q(0)+q(1))
    Yield q.Dequeue 
  End While
End Function




If you are feeling adventurous implement the enumerator implementations of these examples (without using iterator of cause).

Is This A Good Question/Topic? 4
  • +

Page 1 of 1