Comparing MDELite with ATL's Families to Persons Demo


The Atlas Transformation Language (ATL) is a first-generation MDE language for writing model-to-model (M2M) transformations.  As such it is pioneering work against which future transformation languages should be compared.  We invite readers to visit and digest the ATL example at:

http://wiki.eclipse.org/ATL/Tutorials_-_Create_a_simple_ATL_transformation

Here is an MDELite implementation of the Familes to Persons example.  Here is the input database:
dbase(families,[family,member]).

table(family,[id,"lastName",fatherid,motherid]).
family(f1,'March',m1,m2).
family(f2,'Sailor',m5,m6).

table(member,[mid,"firstName",sonOf,daughterOf]).
member(m1,'Jim',null,null).
member(m2,'Cindy',null,null).
member(m3,'Brandon',f1,null).
member(m4,'Brenda',null,f1).

member(m5,'Peter',null,null).
member(m6,'Jackie',null,null).
member(m7,'David',f2,null).
member(m8,'Dylan',f2,null).
member(m9,'Kelly',null,f2).  
and here is the translated database, the output of the Families2Persons transformation:
dbase(persons,[person,male,female]).

table(person,[id,"fullName"]).

table(male,[id,"fullName"]).
male(m1,'Jim March').
male(m5,'Peter Sailor').
male(m3,'Brandon March').
male(m7,'David Sailor').
male(m8,'Dylan Sailor').

table(female,[id,"fullName"]).
female(m2,'Cindy March').
female(m6,'Jackie Sailor').
female(m4,'Brenda March').
female(m9,'Kelly Sailor').

subtable(person,[male,female]). 
In the following sections, I explain the Families2 Persons transformation program.

1. Initialization

The command-line input to the program is the input database (whose contents I listed above).  Read the command line, extract the input file (database) name, and locate the output schema file:
        // Step 1: standard marquee processing
Marquee1In_1Out mark = new Marquee1In_1Out(FamiliesM2M.class,
".families.pl", ".persons.pl", args);
String inputFileName = mark.getInputFileName();
String outputSchema = correct + "persons.schema.pl";

2. Read in Database Input Tables

Next, read in the database, and get the family and member tables:
        // Step 2: read the families database and their tables
DB in = DB.read(inputFileName);
Table fam = in.getTableEH("family");
Table mem = in.getTableEH("member");

3. Read in Schema and Initialize Empty Output Tables

Read in the persons schema, create a new (and empty) database instance of this schema.  Get the empty male and female tables in which we are to populate tuples:
        // Step 3: create an empty persons database with empty tables
DBSchema outSchema = DBSchema.read(outputSchema);
DB inria = new DB(in.getName(), outSchema);
Table male = inria.getTableEH("male");
Table female = inria.getTableEH("female");

4. Perform the Model-to-Model Transformation

The join of the family and members table connects individuals with their family.  Male tuples are fathers and sons of families; Female tuples are mothers and daughers of families.  Four lines compute all male and female tuples:
        // Step 4: fill in father tuples, mother tuples, son, then daughter
fam.join("fatherid", mem, "mid").forEach(t -> helper(male, t));
fam.join("motherid", mem, "mid").forEach(t -> helper(female, t));
fam.join("id", mem, "sonOf").forEach(t -> helper(male, t));
fam.join("id", mem, "daughterOf").forEach(t -> helper(female, t));

The above code, as in the ATL example, uses a helper function.  It takes a table and a join tuple (which belongs to the cross-product of the member and family database) as input.  From the tuple I extract the member's identifer, first name, and last name.  The first and last names are concatenated, and to the input table, I add a tuple whose field values are member identifier, first+last name:
    static void helper(Table tab, Tuple t) {
String id = t.get("member.mid");
String name = t.get("member.firstName") + " " + t.get("family.lastName");
tab.add(id, name);
}

An alternative -- and equally as general  -- is to define correspondences between columns of tuples of dfferent schemas:
        ColumnCorrespondence c = new ColumnCorrespondence()
.add("id",t->t.get("member.mid"))
.add("fullName",t->t.get("member.firstName") + " " + t.get("family.lastName"));

male.add(fam.join("fatherid", mem, "mid"),c);
female.add(fam.join("motherid", mem, "mid"),c);
male.add(fam.join("id", mem, "sonOf"),c);
female.add(fam.join("id", mem, "daughterOf"),c);

5. Print the Persons Database

Is all that remains to do:
        // Step 5: print out database
inria.print();

Homework

Compare the above solution to that of ATL.  I argue MDELite has the following advantages: