Steffen Mazanek writes about an interesting
metamodeling practical that he's conducting:
students have to implement a cut-down UML Class Diagram editor
using
MetaEdit+,
Eclipse
GMF or Microsoft
DSL Tools. It reminds me of the "Use Case cartoon" experiment where MetaCase and Microsoft both
built very simple Use Case diagram support in their respective
tools. Doing it with MetaEdit+ was 6 times faster back then, but
hopefully Microsoft have caught up somewhat since then. Mind you,
those figures were when the tools were used by their developers:
when used by students, I'd expect MetaEdit+ to fare better.
Steffen also wrote a nice
mini-review of MetaEdit+ . He especially liked the ease of use, the Symbol Editor and the high level of integration (as opposed to the multiple mapping languages of GMF). He said MetaEdit+ would find it hard to support languages using spatial relations, e.g. VEX, which uses visual containment rather like Venn diagrams. I'm not sure I'd agree with that. Here's a picture of something like VEX: each circular object has its name in bold at the top, and at the bottom a list of the objects that it contains (recursively).

To build the metamodel took a couple of minutes. MetaEdit+ already understands containment via the 'do contents' structure in its MERL generator language. However, that calculates contents based on the enclosing rectangle of the symbol, whereas for VEX it should be based on circles. Otherwise 4 above will be considered as completely contained in 1: true if you think of their enclosing rectangles, but not for the circles. The little bit of generator script that produces the text at the bottom of the circles therefore needed to be a bit longer than just "do contents { id }". Here's what it took:
Report '_contents'
/* report all contents of the current object,
flattening any nesting */
do contents
{ subreport
'_calcMargin' run
if $margin >=
'0' NUM then
:Name endif
}
endreport
We go through all the objects contained in this object, using the standard "do contents" rectangular definition of containment. For each little object we calculate the margin between it and this circle. If it's positive, the little object is contained and we print its name.
Calculating the margin is done in the calcMargin sub-generator, which saves it in a variable called margin. The formula is simple enough, but might take a moment's thought if your geometry is as rusty as mine:
Report '_calcMargin'
variable 'margin' write
/* big object radius - center difference -
little obj radius */
math
width;1
'/2 - '
'((' centerX
'-' centerX;1
')^2 + (' centerY
'-' centerY;1
')^2)^(1/2)'
' - ' width
'/2'
evaluate
close
endreport
Basically we want to check that the big object's radius is bigger than the distance from the centre of the big object to the outer edge of the little object. The distance to the outer edge is the distance between the centres, plus the radius of the little circle. The distance between the centres is calculated with Pythagoras' theorem, and the radii are just half of the width of the objects. CenterX and width here refer to the little object, whereas the ;1 suffix in width;1 makes it return the width of the big object, one level further out on the element stack -- i.e. from outside the "do contents" loop.
When drawing the symbols, MetaEdit+ thus calculates and displays this list of contained objects. It's even updated on the fly as you drag and scale objects. This lets you do cool things like show big red error signs if someone drags an object into the wrong kind of container.
Putting _calcMargin in its own sub-generator allows us to reuse it from other generators, e.g. to produce an indented "tree" listing showing the containment hierarchy of all the objects (like the default "Object Nesting" generator in MetaEdit+).