The mixin Composition Tool

mixin is a tool to compose .jak files.  Another document presents the big picture of how and where mixin is used, the syntax and semantics of .jak files, and how mixin differs from the jampack composition tool. This document discusses detailed use and features of mixin.

Command-Line Invocation

To call mixin from the command line:

> mixin
Usage: mixin [options] baseFile extensionFile1 extensionFile2 ...
Options: -t (ignored)
         -k (ignored)
         -a <layerName> name of layer to generate
         -f <fileName> name file to generate

Interface Composition Rules

The rules of interface composition that are specific to mixin are:

An example root interface and refinement are:

layer IRoot1;

import java.io.Serializable;

interface MyInt extends FooInterface {
    int Silent = 0;
    void foo() throws AFit;
    SomeType bar( int x );
}

layer Iext1;

public transient refines interface MyInt extends yyyInterface {
   int Terse = 2;
   void foo() throws SomeException;
   int increment( int i );
}

The mixin composition of the IRoot1 and Iext1 files above is shown below, where the yellow-highlighted text is generated by mixin:

layer IRoot1;

import java.io.Serializable;

SoUrCe Base IRoot1 "../Iroot1.jak";

abstract interface MyInt$$IRoot1 extends FooInterface {
    int Silent = 0;
    void foo() throws AFit;
    SomeType bar( int x );
}

SoUrCe  Iext1 "../Iext1.jak";

public transient interface MyInt extends yyyInterface, MyInt$$IRoot1 {
   int Terse = 2;
   void foo() throws SomeException;
   int increment( int i );
}

Note that mixin simply makes explicit the inheritance hierarchy that the composition of these two files represents.  That is, the MyInt interface of layer Iext1 extends the MyInt interface of layer IRoot1.  You'll note that the name of the MyInt interface of IRoot1 has changed to MyInt$$IRoot1 -- because in Java, interface names must be unique.  The bottom-most interface of the refinement chain is MyInt (the name that we wanted). The mangling of a "name" is always "name$$name-of-layer".  Note the bottom-most interface is public, whereas the other interfaces are abstract.

Exercise

Create separate files IRoot1.jak and Iext1.jak to hold the above definitions.  Compose them into C.jak by the command:

> mixin IRoot1.jak Iext1.jak > C.jak

Caveat. Note: the file naming convention used in this example isn't typical.  Usually IRoot1.jak would be a file in the IRoot1 layer (i.e., it would have the pathname IRoot1/MyInt.jak) and Iext1.jak would be a file in the Iext1 layer (i.e., it would have the pathname Iext1/MyInt.jak).  So a more typical invocation would be:

> mixin IRoot1/MyInt.jak IIext1/MyInt.jak > C.jak

Class Composition Rules

mixin composes classes much the same way as it does interfaces. (See the rules for interfaces). A single file is produced that contains an inheritance hierarchy of classes.  The last class that is listed is the public class, all other classes are abstract whose names have been mangled.

Consider the following root class and a refinement:

layer Ctop;

import jakarta.util.*;

class top {
   static int i,j;

   top() {  ii = 5; }

   void foo(float x, float y) { /* do something */ }
   float bar( float x ) { /* do something */ }
}

layer Cmid;

import AnotherPackage;

refines class top implements java.io.Serializable, xxx {
   static int k;

   top(float x) { /* do something */ }

   float foobar() { Super(float).bar(4.0);
                    Super(float,float).foo(0, 0); }

   public void foo( float x, float y ) { /* something more */ }
}

Their mixin composition is shown below.  The yellow-highlighted text is generated by mixin.

layer Ctop;

import jakarta.util.*;
import AnotherPackage;

SoUrCe RooT Ctop "../Ctop.jak";

abstract class top$$Ctop {
   static int i,j;

   top$$Ctop() { ii = 5; }

   void foo(float x, float y) { /* do something */ }
      float bar( float x ) { /* do something */ }
}

SoUrCe Cmid "../Cmid.jak";

class top extends top$$Ctop implements java.io.Serializable, xxx {
   static int k;

   top(float x) { /* do something */ }

   float foobar() { Super(float).bar(4.0);
      Super(float,float).foo(0, 0); }

   public void foo( float x, float y ) { /* something more */ }
}

Exercise

Create separate files top.jak and mid.jak to hold the definitions above.  Compose them into combined.jak by the command:

> mixin top.jak mid.jak > combined.jak

Don't forget the caveat.

State Machine Composition Rules

mixin composes state machine definitions much the same way as it does interfaces.  (See the rules for interfaces). A single file is produced that contains an inheritance hierarchy of state machines.  The last class that is listed is the public state machine, all others are abstract whose names have been mangled.  Here is an example root state machine and a refinement:

layer rootSm;

State_machine root {

   Delivery_parameters( M m );
   Unrecognizable_state { ignore(m); }

   States g, h, i;
   Transition e1 : g -> h 
   condition m!=null
   do { gh(); }
}

layer extSm;

refines State_machine root {

   States j, k;

   Transition e3 : g -> j 
   condition m!=null
   do { Super(int).anotherAction(6); }
}

The mixin composition of the above files is shown below.  The lines in yellow were generated by mixin:

layer rootSm;

SoUrCe RooT rootSm "../RootSm.jak";

abstract State_machine root$$rootSm {

   Delivery_parameters( M m );
   Unrecognizable_state { ignore(m); }

   States g, h, i;

   Transition e1 : g -> h
   condition m!=null
   do { gh(); }
}

SoUrCe extSm "../ExtSm.jak";

State_machine root extends root$$rootSm {

   States j, k;

   Transition e3 : g -> j
   condition m!=null
   do { Super(int).anotherAction(6); }
}

Exercise

Create separate files root.jak and mid.jak to hold the above definitions.  Compose them into result.jak by the command:

> mixin root.jak mid.jak > result.jak

Don't forget the caveat.

Local Declarations

Local_Id declarations are used to avoid inadvertent capture. Consider the following root specification with local identifiers i, j, ii, jj, and foo.

layer Ctopp; 

Local_Id i, jj, foo;

class topp {
   static int i;
   int jj;

   void foo(float x, float y) { i = jj = x+y; }
}

Now consider an refinement that uses exactly the same identifiers locally:

layer Cmidd;

Local_Id i, jj, foo;

refines class topp {
   static int i;
   int jj;

   void foo(float x, float y) { i = jj = x*y; }
}

mixin composes these two specifications to yield:

layer Foo;

SoUrCe RooT Ctopp "../Ctopp.jak";

abstract class topp$$Ctopp {
   static int i$$Ctopp;
   int jj$$Ctopp;

   void foo$$Ctopp(float x, float y) { i$$Ctopp = jj$$Ctopp = x+y; }
}

SoUrCe Cmidd "../Cmidd.jak";

class topp extends topp$$Ctopp {
   static int i$$Cmidd;
   int jj$$Cmidd;

   void foo$$Cmidd(float x, float y) { i$$Cmidd = jj$$Cmidd = x*y; }
}

Exercise

Create separate files topp.jak and extp.jak to hold the definitions above.  Compose them into result.jak by the command:

> mixin -a Foo topp.jak extp.jak > result.jak

 ATS Home Page

Copyright Software Systems Generator Research Group. All rights reserved.
Revised: January 25, 2006.