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
|