class Main {
static inline function main():Void {
var arr = new Arr<Int>();
for (i in 0...10) {
arr.push(i);
}
var iterator = Iterators.map(arr.iterator(), function(x) return x );
// ok
var iterator:MapIterator<Int, Int, ArrIterator<Int>> = Iterators.map(arr.iterator(), function(x) return x );
// Compile error: MapIterator<Int, Int, ArrIterator_Int> should be MapIterator_Int_Int_ArrIterator_Int
var iterator = Iterators.map(arr.iterator(), function(x) return x );
while (iterator.hasNext()) {
trace(iterator.next());
}
// ok
var iterator = Iterators.map(arr.iterator(), function(x) return x );
for (x in iterator) {
trace(x);
}
// Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
var iterator = Iterators.map(arr.iterator(), function(x) return x );
function foo(iterator) { }
foo(iterator);
// Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
var iterator = Iterators.map(arr.iterator(), function(x) return x);
function bar(iterator:MapIterator<Int, Int, ArrIterator<Int>>) { }
bar(iterator);
// Compile error: MapIterator<Int, Int, ArrIterator_Int> should be MapIterator_Int_Int_ArrIterator_Int
genericTakeIterator(Iterators.map(arr.iterator(), function(x) return x));
// Ok
var iterator = Iterators.map(arr.iterator(), function(x) return x);
genericTakeIterator(iterator);
// Runtime error: Type Coercion failed: cannot convert MapIterator_Int_Int_ArrIterator_Int to MapIterator.
}
@:generic
static inline function genericTakeIterator<T, I:Iterator<T>>(iterator:I):Void {
while (iterator.hasNext()) {
trace(iterator.next());
}
}
}
class Iterators<T> {
@:generic
static public inline function map<T, R, I:Iterator<T>>(iterator:I, func:T->R):MapIterator<T, R, I> {
return new MapIterator(iterator, func);
}
}
@:generic
class MapIterator<T, R, I:Iterator<T>> {
public inline function new(iterator:I, func:T->R) {
_iterator = iterator;
_func = func;
}
public inline function hasNext():Bool {
return _iterator.hasNext();
}
public inline function next():R {
return _func(_iterator.next());
}
private var _iterator:I;
private var _func:T->R;
}
@:generic
class Arr<T> {
public inline function new() {
_array = [];
}
public inline function push(item:T):Void {
_array.push(item);
}
public inline function iterator():ArrIterator<T> {
return new ArrIterator(_array);
}
var _array:Array<T>;
}
@:generic
class ArrIterator<T> {
public inline function new(array:Array<T>) {
_array = array;
_i = 0;
}
public inline function hasNext():Bool {
return _i < _array.length;
}
public inline function next():T {
return _array[_i++];
}
var _array:Array<T>;
var _i:Int;
}