Well your solution does work I think. It feels a bit like what Scala is doing
in their collection library. But on the other hand Scala is on the JVM and the
JVM is as badass that it can incline virtual methods. I think in the real world
it really is a lot of overhead, that you do not want in your approach. I tried
once to implement the same with just iterators, but sadly I was limited by the
language:
iterator filter[T](arg: iterator(): T; cond: proc(arg: T): bool): T =
for x in arg:
if cond(x):
yield arg
iterator map[T,U](arg: iterator(): T; fun: proc(arg: T): U): U =
for x in arg:
yield fun(x)
let data = [1,2,3,4,5,6,7,8,9]
for x in filter(data.items(), proc(arg: int): bool = arg mod 2 == 1) ##
undeclared field items, meh...
The language should just have some automatic feature to raise any iterator type
to a closure iterator bundled with their arguments. Otherwise it is just meh to
use, and I will avoid to design an API that is based on it, because it just
feels not thought through to the end.
Something that might actually work very well, is when you write macros to
define your own language within Nim.
macro dataLanguage(arg: untyped): untyped =
[...]
dataLanguage:
var result = myData.filter(_.name.len < 7).filter(_.age >
30).map(_.birthday)
Then you would have total control on how these expressions get compiled. They
can be reduced to a single loop. You could inject commands for memory mapping,
and even inject commands for managing a cloud of computers over a network. It
is certainly the most powerful solution, but also very hard to do the right
thing. I could totally understand, when you do not want to do that. I used
scala notation here for the macro, and that would be possible. The _ is where
the argument is inserted.