HeronFront

HeronFront is a tool which translates Heron trait reference types into C++ classes.

Heron Trait

Heron traits are similar to Scala traits with some enhancements. Like Scala, in Heron a trait corresponds to a type, similar to Java interfaces. For example here is the a Stack trait in Heron:

  trait Stack[type Element] {

    requires {
      def push(Element x);
      def pop() : Element;
      def is_empty() : bool;
    }
  }

The C++ code generated for trait references act as polymorphic pointers to any objects which implement a trait's requirements.

Unlike Java and Scala, Heron traits support structural subtyping (a.k.a duck typing). This means that a trait reference type can be bound to any class which provides the required function signatures. For example consider the following C++ class which implicitly implement the Heron Stack trait:


  struct simple_stack {

    simple_stack() : cnt(0) { }

    static const int max = 42;

    void push(int n) {
      if (cnt > max) throw 0;
      data[cnt++] = n;
    }

    int pop() {
      return data[--cnt];
    }

    bool is_empty() {
      return count() == 0;
    }

    int count() {
      return cnt;
    }

    int get(uint n) {
      return data[n];
    }

    void set(uint n, int x) {
      data[n] = x;
    }

  private:

    int data[max + 1];
    int cnt;
  };
The simple_stack class can then be used with the generated trait reference object as follows:
  void fill_stack(Stack<int> stack, int cnt) {
    for (int i=0; i < cnt; ++i) {
      stack.push(i);
    }
  }

  int main(int argc, char* argv[])
  {
    simple_stack stack;
    fill_stack(stack, 13);
    return 0;
  }
Like Scala traits, and unlike Java interfaces, Heron traits allow the definition of new functions which call trait functions. For instance:

  trait Indexable[type Element] {

    requires {
      def get(uint n) : Element;
      def set(uint n, Element x);
      def count() : uint;
    }

    public {
      def is_empty() : bool {
        return count() = 0;
      }
    }
  }
Where Heron becomes even more interesting is that it introduces partially implemented required functions. These have a huge benefit of enforcing behavioral subtyping by verifying preconditions and postconditions of the various member functions. For example the Stack trait can be written as:

  trait Stack[type Element] {
    requires {
      def push(Element x) {
        _override;
        assert(!is_empty());
      }

      def pop() : Element {
        assert(!is_empty());
        _override;
      }
      def is_empty() : bool;
    }
  }
The _override keyword delegates the function call to the appropriate concrete implementation of the function. This is an example of programming with contracts, where the trait not only specifies the interface, but the contractual obligations of the implementation.

The idea of introducing semantic information into traits addresses one of the biggest concerns with interfaces and structural subtyping, which have been raised numerous times by countless professionals and researchers.

For example a recent blog post at Artima by Eamonn McManus, brings up the issue of lack of behavioral (or semantic) information in Java interfaces as a reason to be prudent with the usage of Java interfaces.

Integrating HeronFront Generated Code

In order to integrate HeronFront generated code into a C++ project you need to include the header "heron.hpp". This provides some important type definitions. The HeronBack project demonstrates how to do this.

HeronFront generated code is currently only tested to work on Visual C++ 7.1, though comments on issues with any other compliant compilers are welcomed. Older or non-conforming compilers are not ever going to be supported.

Implementation of HeronFront

HeronFront is public domain code, written in C++, which was developed using a public domain parsing library called the YARD parser (Yet Another Recursive Descent Parser). The YARD parser is a metaprogramming library which allows the construction of efficient recursive descent parsers using a syntax which resembles EBNF notation. Grammar productions are defined as types, for instance:


  struct Comment :

    bnf_or<

      SingleLineComment,

      FullComment

    >

  { };

The YARD library is briefly explained at http://www.ootl.org/yard/ however a more complete reference is under development by Max Lybbert.

History

The original HeronFront was written in Delphi and featured in the September 2004 issue of C/C++ User Journal, Interfaces in C++. It was designed originally as a proof of the improvements that could be gained by introducing interfaces into C++ as a replacement for using ABC's (abstract bases classes).

References

http://www.iam.unibe.ch/~scg/Archive/PhD/schaerli-phd.pdf Traits: Composable Units of Behavior Nathanael Schärli, Stéphane Ducasse, Oscar Nierstrasz, and Andrew P. Black University of Berne / OGI School of Science & Engineering, May 2003 Proceedings of ECOOP 2003

Copyright 2004, Christopher Diggins, http://www.cdiggins.com