In the course of working on Gem I have identified and developed something I'm calling the Lattice Metamodel. The simplest way to think of it is as an array of trees where every tree has the same shape. I had started with a simple parse tree (as I often do) and was trying to pull semantic information out of the tree in small increments. Over time I could see several trees with data flowing from one to another. After more time I started to think of this as a lattice with many layers where you can navigate both the tree structure of an individual layer and between layers.
I think it's interesting to compare this idea with
attribute grammars where information flows up and down in a single tree. There is also a similarity with
neural networks where groups of neurons are often organized into layers. I'm not much of a theoretician. I'm more of a practitioner who fiddles around with stuff like this in the hopes that it will make code smaller, simpler and more readable. So for me the key challenge was to think of the lattice as a programming model and make it easy to write code that operates on (and in) the lattice.
Below is a screenshot of the class hierarchy of the lattice metamodel. In case you can't tell, these are Java classes viewed in
Eclipse.

Everything is a Part (just as in UML everything is an "Element"). The primary tree of the lattice (that defines the tree shape for all the layers) is rooted at a Model part. The rest of this tree is composed of Figures and Sites. Each Figure may contain zero or more Sites and each Site contains zero or one Figure. Note that a Model is a kind of Site.
Models have a collection of Layers. Figures and Sites are "Faceted" which means they each have a collection of Facets. Each Facet is an intersection between a Layer and a Faceted part. The diagram below shows an example model with two layers.

(The black vertical and diagonal lines show the containment relationships. The blue horizontal lines are simply showing the "sibling" relationship created when two parts have the same parent.)
Imagine overlaying the three trees on top of each other and having a series of vertical connections that tie each Faceted part to the two Facets above it.
The only class not yet mentioned is Environment which is essentially just a collection of Models.
Extending the LatticeEach of the Part classes has an associated Extension class, but I'm just going to discuss LayerExtension and FacetExtension here. The role of the Part classes is simply to describe the structure of the lattice. The Extension classes are for introducing interesting behavior into this structure.
If you want to implement a new Layer you subclass LayerExtension and register it with an Eclipse extension-point. There are a few methods you need to implement. One expresses the dependencies that your Layer has on other Layers. Another is sort of a factory method for FacetExtensions - given a Facet you must return a FacetExtension to be associated with the Layer. Beyond this you can add whatever code you want to the LayerExtension to implement the behavior you need.
You can use a single FacetExtension subclass for your layer or derive a more complex class hierarchy. There are currently no abstract methods in FacetExtension that you must implement. As before you can add whatever Java code you need to satisfy the purpose of the layer.
Once a FacetExtension is created for a Facet, that instance will remain on the Facet until the Facet is destroyed (which will happen when the base Figure or Site is destroyed). This behavior could perhaps be relaxed but it's low on my todo list.
Navigating the LatticeFaceted, Facet and FacetExtension have methods to support easy navigation through the lattice. These methods are based on the terminology shown in the figure below:

So getSuperior() returns the Part or Extension immediately above (towards the root of the tree) and getSubordinate(int) returns the one below indicated by the index parameter. These methods have the (often annoying) characteristic that they flip-flop you from Figures to Sites and back. Often you want to orient yourself on either Figures or Sites and then navigate around. For this you can use getSup() and getSub(int). There is a getSize() method which returns the number of subordinates. Since getSize() will always return 1 (or 0) for a Site, there is also a getSize(boolean) which allows you to skip through Sites (when using getSub(int)). (There should be methods like getSubs() and getSubordinates() that return an unmodifiable list, I just haven't been bothered enough to implement them yet).
The FacetExtension variants of the methods take a Class parameter. This allows a sort of diagonal movement through the Lattice. Imagine you are are implementing FooFacet. You could write getSuperior(BarFacet.class) to get the FacetExtension above and on the BarLayer.
In addition to lateral (and diagonal) movement we need to navigate directly between layers and also back and forth between the Extensions and the Parts. There are methods for all of this. A typical thing is to go from one FacetExtension to another. Again imagining a FooFacet, we could write getFx(BarFacet.class) to get the FacetExtension of the BarLayer associated with the same Faceted part.
Similar to getFx(Class) there are getLx(Class) methods to return a specific LayerExtension. So you could write getLx(BarLayer.class) to get the BarLayer.
Figures and SitesWhy do we even need Sites? We could get rid of them and halve the size of this (fairly huge looking) data structure. Perhaps the best answer I have is that my intuition tells me to keep the Sites for now. Here's some of the thinking behind the intuition:
What is modeling? My one sentence definition of software modeling goes something like this:
Given a reasonable definition of "software object", software modeling is about formalizing (or making "first-class") the relationships between objects.
Another definition I like is:
A model is a collection of objects with managed relationships.
If you are an EMF programmer, you should at least partially agree. One of the great things about EMF is that it generates all the hairy code necessary to manage the references and keep everything well connected.
So going back to Figures and Sites, I think of Figures as the "elements" or the primary points of interest and Sites are the first-class representation of the relationship between Figures.
Of course Sites are just a representation of the
containment relationship. There are many other kinds of relationships to model. So let me go even farther out on a limb: In the Lattice Metamodel, I'm treating the containment relationship as the fundamental relationship in the modeling system. Other kinds of relationships will be implemented in Layers (and discussed in other posts).
Another bit of (possibly faulty) intuition: I like to think of Sites as "neutral ground" between Figures, because I've run into a lot of tree programming situations where I have data that doesn't seem to belong either to the parent or child node - it needs to be shared by both on equal terms.
So for now the Sites stay.