Skip to content

Iterable <Iterable<T>> in haXe

February 6, 2009

One of the (few) limitations of haXe is that it does not structurally type collections recursively, either through the type itself, or a type parameter.  So, writing a function header of :

public function (it:Iterable<Iterable<T>>) : …{}

will not work in the intended way.  In fact, trying to pass a List<List<T>> or [[1,2,3],[4,5,6]] for “it” will cause errors.

This is a limitation for functional programming routines, especially functions that handle collections of collections like chain, zip, etc.

In order to handle these situations, it’s necessary to come up with a work-around.  For relevant methods, I have a function header that looks like:

function(it:Iterable<Dynamic> , ?nonIterableBehavior<Dynamic>->Iterator<Dynamic>):…

The “it” parameter is a simple single collection of any Type (Dynamic).  This will accept Iterable<Iterable<T>>, but also Iterable<T>, or a mixed Iterable of both iterable/non-iterable elements.  I’m mainly interested in the first case, but I’ll have to handle the latter two cases as well.

In order to handle the all of the cases, it’s necessary to detect if an individual element T is actually an Iterable<T2> (T2 equals some other type).  The straightforward method would be to use Reflect.hasField(“field”, iterator).  However, this will not detect the iterator() in Arrays.  Also, since we’re using a Dynamic type, we’ll have to test for null.  In the end, this should work for an Iterable tester:

public static function isIterable(d:Dynamic):Bool{
return (d != null && (Reflect.hasField(d,’iterator’) || Std.is(d, Array)));
}

As long as the object has an “iterator” field function that behaves in a consistent way, this will work for it.

Now that we can test for Iterables, we can handle non-iterables.  In relevant functions I use a function called nonIterableBehavior that transforms these non-iterables into Iterators, and then pass that resulting iterator along to chain as if it were a proper Iterator.  In my own classes, nonIterableBehavior defaults to something I thought would be appropriate.  For instance, in chain(), the default nonIterable function applies IterTools.repeat(“x”,1) to the non-iterable element.  In zip(), the default nonIterable function instead skips any nonIterable elements  (skipping is assumed by a function that returns null).

So… the net effect is that I can now call something like

ListTools.chain([[1,2,3,4],5,[6,7,8]])

and get back a List<Dynamic>:

{1,2,3,4,5,6,7,8}

From here, if I need to do anything further with the elements in the list, I’ll have to type check everything with Reflect/Std.is methods like Std.is(x,Float), etc.  However, in most of my cases, just printing out a list is useful.

From → haXe, Manipulation

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: