Skip to content

Epsilon and EMF

Below are some frequently-asked questions related to querying and modifying EMF-based models with Epsilon.

What is the difference between containment and non-containment references in EMF?

Briefly, a model element can belong to as most one containment reference at a time. Containment references also demonstrate a cascade-delete behaviour. For example, consider the following Ecore metamodel (captured in Emfatic).

package cars;

class Person {
  ref Person[*] friends; //non-containment reference
  val Car[*] cars; // containment reference
}

class Car { }

Now consider the following EOL code which demonstrates the similarities/differences of containment and non-containment references.

// Set up a few model elements to play with
var c1 = new Car;
var c2 = new Car;
var p1 = new Person;
var p2 = new Person;
var p3 = new Person;

// p1's car is c1 and p2's car is c2
p1.cars.add(c1);
p2.cars.add(c2);

// p3 is a friend of both p1 and p2
p1.friends.add(p3);
p2.friends.add(p3);

p1.friends.println(); // prints {p3}
p2.friends.println(); // prints {p3}

//add c2 to p1's cars
p1.cars.add(c2);
p1.cars.println(); // prints {c1, c2}

// The following statement prints an empty set! 
// As discussed above, model elements can belong to at 
// most 1 containment reference. As such, by adding c2 to
// the cars of p1, EMF removes it from the cars of p2
p2.cars.println();

// Delete p1 from the model
delete p1;

Person.all.println(); // prints {p2, p3}

// The following statement prints an empty set!
// As discussed above, containment references demonstrate
// a cascade-delete behaviour. As such, when we deleted p1,
// all the model elements contained in its cars containment reference
// were also deleted from the model. Note how the friends of p1 (p2 and p3)
// were not deleted from the model, since they were referenced through a 
// non-containment reference (friends)
Car.all.println();

How can I get all children of a model element?

Epsilon does not provide a built-in method for this but you can use EObject's eContents() method if you're working with EMF. To get all descendants of an element, something like the following should do the trick: o.asSequence().closure(x | x.eContents()). See https://www.eclipse.org/forums/index.php/t/855628/ for more details.

How can I get the container of a model element?

Epsilon does not provide a built-in method for this but you can use EObject's eContainer() method if you're working with EMF.

How can I use an existing EMF Resource in Epsilon?

To use an existing EMF Resource in your Epsilon program, you should wrap it as an InMemoryEmfModel first.

How can I use custom load/save options for my EMF model?

You need to un-tick the "Read on load"/"Store on disposal" options in your model configuration dialog and use the underlying EMF resource's load/save methods directly from your EOL code. For example, to turn off the OPTION_DEFER_IDREF_RESOLUTION option, which is on by default in Epsilon's EMF driver and has been reported to slow down loading of models that use "id" attributes, you can use the following EOL statement.

M.resource.load(Map{"DEFER_IDREF_RESOLUTION" = false});