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.

Reply via email to