Multiple Function Outputs? Design questions
Kernel | Home

  Background

A young spiritual pilgrim asked an old sage, "What holds up the world?"
"The world rests on the back of a giant turtle," the sage replied.
"And what holds the turtle up?"
The sage paused a moment, then said, "It's turtles all the way down!"

  The Question

Update: Some parts of this problem are now solved -- see notes below.

A current bug in the kernel highlights an important design question: what's at the top of the tree of elements? The bug is simple: it's possible to create two elements with the same full name if both their superelements are null. The reason that the kernel currently misses this is that it enforces name uniqueness one element at a time, in Element.Compilation.checkLazy(). This is a fine approach -- it mirrors the semantics nicely. The only problem is that there's nobody to check the names of elements with no superelement. Answer: Separating the ideas of "container" and "element" in the semantics made room for a new "namespace" class, which fixes this bug. Now every element requires an owner, and a namespace itself has no name and has only a single root element; it's thus no longer legal to create multiple top-level elements with the same name. Problem solved!

The underlying questions here are:

  • What's at the top of the element tree? Is there some object speaking for "null"? If so, what does it represent? Is it an element itself? If not, where do errors associated with it go? Answer: It is a namespace; it is not an element, but both namespaces and elements are containers, and share properties such as being compilable and having errors. This makes lovely semantic sense, and plays out nicely in the implementation.

  • How do elements announce their participation in a program? It should be possible to set up an element in isolation, without having compilers and propagators and notations and such watching it. Given that, how does an element announce that it's ready to join in all the fun? Update: Should an element join the fun when it has a namespace? Is the namespace then responsible for compiling its elements? Or does a namespace have to explicitly be attached to a compiler by some sort of loader?

  • Should one object be responsible for tracking all the existing elements? There need to be two EventQueues which handle compilation and event propagation for all elements. How do individual elements associate themselves up with these common queues? How do notations know when they need to start watching a new element? Engine is currently dealing with some of these questions, but the class is really just a placeholder.

  • How should this topmost element or global organizer correspond to physical code locations? Should the namespace class always corresponds to one self-contained library of code? Or should the kernel attempt to hide the physical sources of code, tracking this element by element in some separate way? If we choose the latter, how should the kernel handle name conflicts between libraries? If it handles it by having an ordered priority of libraries (similar to Java's classpath), is the kernel responsible for exposing elements in one library which are shadowed by another higher-priority library?

  Question Still Open

The namespace class has neatly solved half the problems here, including the bug that spawned this discussion. Before we can answer the remaining questions, however, the needs of notations and storage systems will need to be a little clearer. I prefer to let the uncertainties dangle until we have a better idea of what's really needed, at which point this will no longer be a difficult question.

  Design questions | Kernel | Home Copyright 2000-2001 Paul Cantrell