At the meeting in Chicago, we talked a lot about the editor functions
(svn_delta_edit_fns_t), and various changes people wanted to them. I
generally argued for keeping them unchanged, but I think now I've come
to a better understanding of the situation, and would like to suggest
a different attitude.
Here's the analogy which affected my thinking:
One of Unix's great strengths is the simplicity and uniformity of its
text files. They're a series of bytes, with lines terminated by
single newline characters. Just about everyone reads them and writes
them. Editors know how to edit them. Grep knows how to grep them.
Perl knows how to commit unspeakable sins against humanity on them.
If we had several different forms in widespread use --- fixed-length
records, byte-count-delimited, and so on --- these things would be
harder.
The editor interface was meant to be for tree transformations what
unix files are to textual data --- the universal exchange format.
That's why I've been arguing against the embellishments and
specializations that are often proposed. But the fact is that people
frequently want to do things that just don't fit into the existing
form. The `ancestor_version' arguments were controversial --- they
are relevant only to changes to trees with version numbers, not to
tree changes in general. For DAV, Greg S. wants to be able to get and
put properties on the working directory as we commit changes. So
while we can say that the Unix file format is looking healthy after
decades of technological change, the editor interface is already being
stretched --- and we haven't even made our first release yet!
So here's the thought. This is a major change from the position I've
taken until now, so you can all snicker at me now. :)
What's essential about the editor interface is the depth-first
traversal rule, and how the batons work. Those are the properties
that you really need. Once you've got batons that can carry
information as you walk the tree, and you can make helpful assumptions
about how that walk is going to behave, you can pretty much use or
ignore any other function calls as you please.
So, let's declare open season on adding new functions to the editor
structure. We retain the essential rules about add_*, replace_*, and
close_*. Those are the only functions that create new batons, or
close batons. You still have to use them in a depth-first order. But
you can add other functions that do whatever you like to the batons
while you've got them. When I discussed this on the phone with the
Chicagoans this morning, Karl said that he'd suggested moving the
ancestor_revision argument to separate functions, to be applied to the
appropriate batons when needed. Each editor will have to document
which functions it supports and requires, and each driver will have to
document which functions it calls.
Of course, we still need to choose new functions carefully. The
better our factoring, the more likely it is that we'll be able to
randomly plug editors together in unusual ways.
If we go with this approach, I'd suggest we change the way we handle
svn_delta_edit_fns_t structures a bit.
At the moment, every editor simply has a statically initialized
svn_delta_edit_fns_t structure initialized with appropriate function
pointers, like `tree_editor' in libsvn_wc/get_editor.c, or
`trace_editor' in client/trace-commit.c. Every time we add a new
function to svn_delta_edit_fns_t, we need to fix each of these
declarations, even if it's just to add a null, or a dummy function.
Instead, libsvn_delta should provide the following function:
/* Allocate and return a new function table for the `dummy' editor ---
one which ignores every function called on it. This editor uses
the null pointer for all its batons. All function pointers are
initialized to dummy functions. You needn't test whether a
function pointer is non-zero before using it --- you can just call
the function.
Real editors should construct their own function tables by calling
this function, and then installing pointers to their own functions
for the editor operations they care about. This rule allows us to
extent svn_delta_edit_fns_t with new functions without having to
change the code for all the editors that don't care about the new
function.
Allocate the function table in POOL. */
svn_delta_edit_fns_t *svn_delta_make_edit_fns (apr_pool_t *pool);
I'm not dogmatic about the details here. The point is simply to allow
source code for editors to be dependent only on the portions of
svn_delta_edit_fns_t they actually use, so we won't hesitate to extend
it as necessary. The same situation arose in GDB, with several dozen
implementors of a large function table, and this solution has been
working pretty well.
Received on Sat Oct 21 14:36:19 2006