Rogue Augments

Rogue now has a nice new ability in its object-oriented tool-set: the augment. Originally appearing in Slag, I've brushed off the augment and expanded its capabilities.

At its simplest you can use an augment to define a single class in several different pieces. Any properties and methods defined in the augment will be copied into the target class as if you had typed them in there originally:

class Test
  METHODS
    method init
      display
endClass

augment Test
  METHODS
    method display
      println "Augment"
endAugment

Test()  # prints: Augment

If the target class already contains a method that appears in the augment, the augment's code is inserted into the original method definition:

class Test
  METHODS
    method init
      display

    method 
      println "Test"
endClass

augment Test
  METHODS
    method display
      println "Augment"
endAugment

Test()  # prints: Augment Testing

If you label a section of augment code with <<append>> then the augment is appended to any existing method rather than inserted:

class Test
  METHODS
    method init
      display

    method display
      println "Test"
endClass

augment Test
  METHODS
    method display
      <<append>>
      println "Augment"
endAugment

Test()  # prints: Testing Augment

The default insertion behavior can also be explicitly specified with the <<insert>> label. And you can have both!

class Test
  METHODS
    method init
      display

    method display
      println "Test"
endClass

augment Test
  METHODS
    method display
      <<insert>>
      println "Before"

      <<append>>
      println "After"
endAugment

Test()  # prints: Before Testing After

Here's the real twist: you can define arbitrary labels in both your regular methods and in augment methods. The various sections of augment code will be inserted into the target methods at the corresponding label positions.

class Test
  METHODS
    method init
      display

    method display
      println "Beta"
      <<middle>>
      println "Delta"
endClass

augment Test
  METHODS
    method display
      <<insert>>
      println "Alpha"

      <<middle>>
      println "Gamma"

      <<append>>
      println "Epsilon"
endAugment

Test()  # prints: Alpha Beta Gamma Delta Epsilon

Here are a few more details:

  1. Any number of labels can be specified in both target methods and augment methods.
  2. Labels in target methods do not have to be filled; they can simply be hooks for possible future augmentation.
  3. Each label in an augment method must match a label in the target method to ensure that code isn't silently dropped.
  4. Any single label in a target method can be filled by code from multiple augments.
  5. The same label can be used multiple times in the same method. In a target method, each occurrence of a label is filled with another full copy of augment code. In an augment method, code under repeat occurrences of a single label is consolidated into a single set of code.
  6. Target labels can be written anywhere and nested within control structures. Augment labels must be written in the outer scope of the method (in other words not inside any control structures).
  7. Any base types (usually aspects) listed in an augment become new base types of the target class.

Rogue augments are a great "lightweight" way to achieve separation of concerns. I've pulled out all of the Rogue compiler code related to generating C++ and put it in a single file in the form of several dozen augments. Now I can easily jump around in that one file to trace through the logic or make broad changes and I can copy the file and start tweaking it to support a new compile target.