C++ makes for a great target language, with its intricate generics and its plethora of other low-level features. We can both succinctly map a high-level language such as Python to its feature set, and leave further optimization to be handled by decades old, mature C++ compilers. In many ways, C++ is really as flexible as Python. The problem is that this flexibility is often hard to achieve, and often results in unreadable code. It's nicer I guess to have a compiler write the C++ code for you :-) Consider the following example:
def flatsie(iter):
return [(b,a) for (a,b) in iter]
flatsie([(1,2.1)])
flatsie({(2,3.141): [1,2,3]})
flatsie({(11,4.1): None})
flatsie(((7.7,1),))
There are some interesting things going on here. If we would like to compile this example to C++, the list comprehension has to be compiled to a generic function. But as the list comprehension iterates over both lists/tuples and dictionaries, it is not immediately clear how to write this nicely in C++, because dict is implemented using two template variables, as opposed to one for list and tuple. C++ provides an elegant solution: make iterable classes inherit from a pyiter
class with a single template variable, and in case of dict, map the right template variable to it. Finally, we would also like to statically preallocate the result of the list comprehension, but since this is a generic list, we cannot define it globally. C++ again has the solution: use the 'static' keyword inside the function template, to create a parameterizable 'global' variable.
As of today, this example compiles cleanly, without breaking any of the other 95 unit tests. As there are only two types of tuples involved, the iterative analysis nicely ends up with two tuple object contours. These tuples are also modeled internally, or the list comprehensions would cause precision loss. Tuples of length greater than two are not yet internally modeled, but this would be a straight-forward generalization. In order to get here, I had to implement generic list comprehensions, and as a result the template milestones now look almost completed. In any case, it's pretty cool to see the compiler output the following working C++ code :D
template [class A, class B] static inline list[tuple2[B, A] *
*list_comp_0(list[tuple2[B, A] *] *result,
pyiter[tuple2[A, B] *] *iter) {
A a;
B b;
tuple2[A, B] *__0;
result->clear();
FOR_IN(__0,iter)
TUPLE_ASSIGN2(a,b,__0,0);
result->append(new tuple2[B, A](b, a));
END_FOR_IN
return result;
}
int main() {
flatsie(new list[tuple2[int, double] *](2, new
tuple2[int, double](1, 2.1), new tuple2[int, double]
(2, 4.1)));
flatsie(new dict[tuple2[int, double] *, list[int] *]
(1, new tuple2[tuple2[int, double] *, list[int] *]
(new tuple2[int, double](2, 3.1),new list[int]
(3, 1, 2, 3))));
flatsie(new dict[tuple2[int, double] *, none *](1,
new tuple2[tuple2[int, double] *, none *](new tuple2
[int, double](1, 4.1),0)));
flatsie(new tuple[tuple2[double, int] *](1, new tuple2
[double, int](7.7, 1)));
}
template [class A, class B] list[tuple2[B, A] *] *flatsie
(pyiter[tuple2[A, B] *] *iter) {
static list[tuple2[B, A] *] __1;
return list_comp_0(&__1, iter);
}
3 comments:
Post a Comment