GWT

Modifying Types

One of the most subtle and important features of StrataCode is the ability for one layer to modify the types in a layer it extends.

The rules for modifying a type work just like the rules for overriding a type in a base class.

You can override property values and methods, and use the super operator to refer to the previous implementation. You can add new fields, new methods or property assignments. A layer can replace the class entirely, replace a field definition, changing it's type and initializer, or it can modify the extends or implements statements of the superclass.

It is only safe to redefine a class where the new class has a superset of the contract from the base layer - i.e. fields and methods which match the parent methods. Layers which preserve the contract maintain compatibility with subsequent layers.

To modify a type, add a file with the same name in a layer which extends that layer. Make sure the full package name and file name of your file match that of the downstream layer or you get an error. Remember the full type name of any file in StrataCode is the combination of the layer's package prefix along with the file name.

Here are a few examples. If in the base layer you define this class:

public class Foo {
   int x;
}

In the sub layer you can modify the class with:

Foo {
   x = 3;
}

The generated Java class will be:

public class Foo {
  int x = 3;
}

You can also override methods just as if you were extending from the Foo class.

public class Foo {
   public void hello() {
     System.out.println("hello");
   }
}

In the sub layer you could do:

Foo {
   public void hello() {
     super.hello();
     System.out.println("goodbye!");
   }
}

The StrataCode compiler generates one class named Foo. The replaced method is renamed superlayerNametypeNamemethodName and all super.method() calls are remapped to the new name.
You can add a new field in one layer:

Foo {
  int newField;
}

and you can replace the field definition with:

Foo {
   public int newField;
}

You can't make incompatible changes in a subsequent layer. For example, this is a compile error:

Foo {
  // Error - can't change the type of a field
  public float newField;
}

A layer can use the override keyword to just change attributes without specifying the type again:

// Adds the final attribute to newField
Foo {
  override final newField;
}

You can also define new sub types and modify existing sub types:

Foo {
   class Bar {  // add's an inner class
     int barProp;
   }
   Baz {  // modify an existing inner class named Baz and override a property 
     bazProp = 3;
   }
}

You can also add or modify object instances:

Foo {
   object bar {  // add's an inner instance of a singleton type named bar
     int barProp;
   }
   baz {  // modify an existing inner object named baz defined in Foo
     bazProp = 3;
   }
}

Or replace the extends class with a compatible type:

Foo extends Fum {  // changes Foo's base class to Fum.
}

Foo either should not have a base class or its base class should be a subtype of Fum to enforce the "compatibility constraint" with layers.

You can use a modifier to modify an inner type which is inherited by the parent type. For example, if I have a base class B, subclass C which extends B, if B defines an inner object, I can modify that in C:

class B {
   object childOfB {  
     int barProp;
   }
}
// OK
class C extends B {
   childOfB {  
     barProp = 3;
   }
}

Note however that in this case, the childOfB modify operator creates a new type in the system. Effectively StrataCode converts this to:

class C extends B {
   object childOfB extends B.childOfB {  
     barProp = 3;
   }
}

This is a subtle but important case to support. It lets you modify the definition of any property underneath your given type, creating new types transparently as needed so that customization is only applied to the right instances.