Sponsored Link •
|
Summary
The latest HeronFront prototype now provides traits which support structural subtyping (duck typing), and behavioral subtyping. This extensions should prove very interesting to people who are interested in agile programming methodologies, and programming with contracts.
Advertisement
|
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.
Have an opinion? Readers have already posted 17 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Christopher Diggins adds a new entry to his weblog, subscribe to his RSS feed.
Christopher Diggins is a software developer and freelance writer. Christopher loves programming, but is eternally frustrated by the shortcomings of modern programming languages. As would any reasonable person in his shoes, he decided to quit his day job to write his own ( www.heron-language.com ). Christopher is the co-author of the C++ Cookbook from O'Reilly. Christopher can be reached through his home page at www.cdiggins.com. |
Sponsored Links
|