On Thursday, January 3, 2013 3:28:52 AM UTC-6, Ville M. Vainio wrote:
Yes, it's indeed an interesting pattern.
It would seem more useful in faster languages than python though; in python, string operations (and gc) are faster in comparison to executing other code, whereas in fast, more static languages (C++, Java, Go) avoiding GC gives you great benefits (I saw 5x perf increase reported for some Go app when eliminating GC).
Thanks for these remarks. I've enjoyed thinking about them. A few responses:
1. This is a smallish pattern--it can't change the world, except insofar as something beautiful changes the world.
2. Otoh, the pattern changes the way I think about lisp and lisp-like patterns. That's not nothing. For the first time, it makes list-oriented programming pattern completely safe. It does this because it doesn't matter what each component list contains, nor does it matter *at all* what the shape of any part of the tree is. This makes the pattern completely flexible.
3. The pattern can be generalized. The pattern I described uses a tree of component strings to describe a (large) resulting string. But one can easily imagine using lists to hold anything at all (of whatever tree shape) and then use another version of flatten_list to compose results of other types. Alternatively, rather than composing a result, the analog of flatten_list could process the tree of lists in other ways. So the most general version of the pattern is:
A) The tree of lists can contain any data whatever, especially including None,
B) The "producers" (visitors) can create subtrees of whatever shape,
C) The analog of flatten_list is free to do anything whatever with the resulting tree.
I suspect that these features are what appeal to lisp programmers ;-)
4. I'm not sure whether the pattern is more useful in "faster" languages or not. True, anything that helps a feeble language like C++ will seem useful :-) But points 1-3 above have nothing to do with speed: they just make programming simpler, more flexible, more powerful and more fun.
Imo, gc issues are important both in Python and in C++. For stc, the only way to get reproducible timing statistics for tests was to do the following before running the test::
for z in (0,1,2): gc.collect(z)
The ReportTraverser class no longer contains *any* calls to string.join, so one could imagine that all strings used in the code would be interned. The generated tree actually contains nothing but *references* to strings, and if all strings are interned the references will not themselves cause any new strings to be allocated.
Naturally, gc issues are even more important in language like C++ without a gc. Lol. The preceding paragraph is more important for C++ than in Python. So yes, in this sense I agree with you completely that the pattern is more useful for "fast" languages than for Python.
Thanks, Ville, for provoking all these pleasant thoughts :-)
Edward