This Engineering Notebook post discusses how to improve Leo's code by using
a more functional programming style, particularly regarding Leo's
generators.
If I were to start Leo today, I would define the methods of the Position
class differently. Don't panic: I'm not going to break existing Leonine
scripts.
Let's look at an example.
*Changes to leoRst.py*
I have just changed the main loops in leoRst.py so that they use a more
functional style. The new code is in the ekr-new-rst branch, along with the
rest of the new rst3 code.
The old code used the pattern:
p = p.copy()
after = p.nodeAfterTree()
while p and p != after:
<< process p, and advance p >>
The new code uses the pattern:
for p in root.self_and_subtree():
<< process p, leaving p unchanged>>
In other words, the old code depends on side effects; the new code does not.
*A more functional Position class*
If I were designing the Position class today, I would make the following
changes:
- Remove (or hide) all p.moveTo* methods.
- Remove (or hide) p.copy()
- Eliminate the evil "copy" kwarg from all iterators.
*The (approximate) effect of these changes would be to make positions
immutable.* Alas, immutable positions do not automatically make it easier
to insert, delete or move nodes. In particular, c.deletePositionsInList
would remain exactly as before.
*Performance issues*
I have glossed over a minor performance issue. The old code skipped
@rst-ignore-tree nodes in the outer loop. The new code skips nodes further
down in the calling tree by testing `self.in_ignore_tree(p)` for *every *node
in the tree. self.in_ignore_tree(p) must search up the tree, so we expect
O(n*log(n)) total time to make all the calls to self.in_ignore_tree(p).
There are easy workarounds for this supposed performance hit. For example,
a prepass could mark to-be-ignored nodes. The time to perform all the tests
would then be O(n).
In practice, such performance problems will never be a problem anywhere in
Leo. Indeed, I expect similar or better performance for functional code.
Python's generators are super fast.
*Summary*
Converting to a more functional style is possible *now*. Just remove calls
to p.moveTo* and adjust accordingly. Bye bye side effects. From time to
time, I'll consider actually making those changes.
If I were designing Leo's Position class today, I would eliminate or hide
the p.moveTo* methods, the p.copy method, and the copy kwarg for all of
Leo's generators. These changes would make positions immutable. However,
the complications involved in changing outlines would remain.
I will make no changes to the Position class that would break existing
scripts. The p.moveTo* and copy methods will remain. I may tweak the
Position class, but such changes will be minor.
All comments welcome.
Edward
--
You received this message because you are subscribed to the Google Groups
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/leo-editor/36878bd1-bb3f-4086-89f1-7cc9b10a8d27n%40googlegroups.com.