Thread Safety is not Necessary

Bill Venners: In your talk you said JDOM taught you that
"Thread safety is not necessary." Why not?

Elliotte Rusty Harold: Thread safety may be necessary in some
applications that use JDOM, but in those applications, the synchronization
probably belongs in the broader
application that's calling JDOM. Many applications are not multi-threaded. And
even those that are multi-threaded do not necessarily share JDOM objects
between multiple threads. There's no reason to put the overhead of designing
for multi-threaded applications into JDOM itself. If you need to share JDOM
documents between multiple threads, then you can synchronize it at a higher
level.

Bill Venners: By that overhead do you mean the performance hit at
runtime, or the extra work programmers have to do to make JDOM
multithreaded?

Elliotte Rusty Harold: Mostly the extra work that programmers have to
do. I don't worry that much about performance. That's there too, but I think
designing truly thread-safe code is incredibly difficult. It really requires an
expert, and I'm not an expert in designing thread-safe code.

Live Lists are Trouble

Bill Venners: You also said that "Live lists are trouble." What are live
lists, and why are they trouble?

Elliotte Rusty Harold: Live lists have troubled both DOM and JDOM.
They are probably a little more trouble in JDOM because the issues haven't
been thought out in as much depth as in DOM. Let's say you have an
Element object, a Document element, and you ask for the
children of that element—all the children, not just one. You get back
a list, and you iterate through the list. In JDOM you get back a
java.util.List. In DOM you get back a
NodeList. In both cases, imagine you delete an element from
the list as you're iterating through the list. Or you add an element to the list,
even within a single thread, modifying the list as you go. In JDOM and DOM, that
changes the children of that element.

You have a real reference to the real children of the element—that's what
a live list is. And if you've got a multithreaded application, if another thread
changes the list, you see that reflected immediately too. Live lists are useful for
some purposes, although not for the most common case of reading through
the list and iterating all the children. It is useful perhaps when you're modifying
the list. However, both JDOM and DOM have a huge amount of extra complexity
internally to support the liveness of their lists. It makes the code much harder to
fix. Both JDOM and some DOM implementations have had serious bugs
related to liveness of lists, in cases where the liveness failed even though it
wasn't supposed to. And it makes it hard to evolve the code.

Bill Venners: So is there another kind of list, a dead list perhaps?

Elliotte Rusty Harold: Yes. Instead of returning a reference to the actual
children, the API can return a copy of the list. The changes made to that list are
not reflected in the original document from which the list came.

XOM lists,
interestingly, are neither live nor dead.
They are in-between, what I refer to as comatose.

In XOM, a change to the list does not change the
document. However, a change to a member of the list does change that
member back in the document. For example, in the list, you remove an element.
It is not removed from the document.
However, if in the list you change the name of an element, call
element.setName(), the name of the element changes in the
document too. The list references to the actual elements in the document, but
the list itself is not the same list used in the document.

Keep Everything in the Same Package

Bill Venners: You also said you learned from JDOM to "keep everything in the same package."

Elliotte Rusty Harold: In JDOM, we had some major troubles with
serialization and parsing, because the parsing went into the
org.jdom.input package, the serialization went into the
org.jdom.output package, and the core classes were just in
org.jdom. We really needed friend functions. The parser or
builder needed to do things that we could not expose in the core package
without exposing them to other non-parser related classes.

For example, we wanted the parser to be able to create an element without
verifying it. Generally speaking, when you construct a JDOM element, the name
and properties of the element are verified to make sure the element is well-formed.
JDOM wants to make sure that client programmers can't bypass those
checks. However, if the parser is building the document, the parser has already
made those checks. So in that case, it is perfectly reasonable to bypass those
checks. Because the parsers are in a different package than the classes
themselves, however, the only access possibility we have is public. So without friend
functions, we really need to keep everything so closely related together in the
same package, so we can use package protection for those special cases.