Collections Tutorial

BlitzMax Forums/BlitzMax Tutorials/Collections Tutorial

TomToad(Posted 2008) [#1]
Collection Tutorial

Here is a small tutorial for writing collections.
A collection is a set of data that can be looped through using For/EachIn/Next. Arrays are collections, so is a TList object. Collections can be the result of incrementing through a formula.

I have decided to make a collection that will help emulate a For/To/Step loop. The advantage is, by changing the data in the collection, you can change the any of the values, including Step, even during the loop. Really nice if, for instance, you want to use one For/Next loop to draw a grid, but the grid spacing, and therefore the Step value, can change dynamically.

To start with, we will put SuperStrict at the top of the program. SuperStrict will help catch many errors and make debugging much easier.
SuperStrict

Next we will create the type. We will put in a Global called Data which will point to an instance of the type. this instance needs to be created since BlitzMAX will ask for one when we enter the For/EachIn loop. Also we will put in Globals called _From, _To, and _Step, which will represent the From, To, and Step fields of a For/Next loop. I'm using an underscore so as not to create conflicts with the BlitzMAX built in commands. Lastly there is a Field called Current which will represent the current value of the loop.
Type TLoop
	Global Data:TLoop
	Global _From:Int, _To:Int, _Step:Int
	Field Current:Int

Now we will create a function Set() which will create a new object for Data, and will set all the fields for us.
	Function Set(_From:Int,_To:Int,_Step:Int)
		Data = New TLoop
		Data._From = _From
		Data._To = _To
		Data._Step = _Step
	End Function

Now, before we actually enter the loop, we set the fields like this
TLoop.Set(100,200,10) Where the first number is the From field, the second is the To field and the last is the Step value.

Next we need to create the ObjectEnumerator() method. When the For/Eachin loop is first entered, BlitzMAX will call this method which will then return an Enumerator type. Since TLoop is the Enumerator itself, it'll just return the TLoop object stored in the Data global. Before it returns though, it will set Current to the _From value minus the _Step value. We are subtracting the _Step value, because through each iteration, we will be adding the _Step value and checking it against the _To value, so that _From value itself will be returned the first time through the loop, we are starting at a lower value. There are other ways of doing this also, such as setting a flag and only incrementing the Current Field on the second and later iterations.
	Method ObjectEnumerator:TLoop()
		Current = _From - _Step
		Return Data
	End Method

Next we are going to create the HasNext() method. Through every iteration of the loop, BlitzMAX will call HasNext() and it will return either True if there are more items in the collection, or false if all the items have been returned. Our HasNext method will just add the _Step value to Current and compare it to the _To value. There are two comparisons depending on whether the _Step value is positive or negative.
	Method HasNext:Int()
		Current :+ _Step
		If _Step > 0
			If Current <= _To Then Return True
		Else
			If Current >= _To Then Return True
		End If
		Return False
	End Method

Next is the NextObject() Method. When HasNext() returns True, BlitzMAX will call NextObject() to get the actual object. Here, we just need to return Data.
	Method NextObject:Object()
		Return Data
	End Method
End Type

And that's it for the type. Now we will just create some code to test. First the code calls TLoop.Set(0,100,5) to set the parameters, then uses For/Eachin to do the actual looping. There are three loops in this example, the third one using a negative step value
TLoop.Set(0,100,5)
For Local Loop:TLoop = EachIn TLoop.Data
	Print Loop.Current
Next
Print "~n"
TLoop.Set(100,200,20)
For Local Loop:TLoop = EachIn TLoop.Data
	Print Loop.Current
Next
Print "~n"
TLoop.Set(500,400,-5)
For Local Loop:TLoop = EachIn TLoop.Data
	Print Loop.Current
Next

Here is the code in it's entirety.

You can look at brl.mod/linkedlist.mod/linkedlist.bmx for another good implementation of collections