Metaprogramming with Traits

Metaprogramming with Traits, Aaron Turon and John Reppy. ECOOP 2007

In many domains, classes have highly regular internal structure. For example, so-called business objects often contain boilerplate code for mapping database fields to class members. The boilerplate code must be repeated per-field for every class, because existing mechanisms for constructing classes do not provide a way to capture and reuse such member-level structure. As a result, programmers often resort to ad ho code generation. This paper presents a lightweight mechanism for specifying and reusing member-level structure in Java programs. The proposal is based on a modest extension to traits that we have termed trait-based metaprogramming. Although the semantics of the mechanism are straightforward, its type theory is difficult to reconcile with nominal subtyping. We achieve reconciliation by introducing a hybrid structural/nominal type system that extends Java's type system. The paper includes a formal calculus defined by translation to Featherweight Generic Java.

This paper explains how to scratch an itch I've had for a long, long time -- uniformly generating groups of fields and methods, including computation of the field/method names. Something like this would be quite useful in an ML-like language's module system, too.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Could this be done using dependent types...

...or a variant thereof, where a) terms of type "symbol" are present and may be depended on by types, and b) the naming of a field in a record is handled by pairs?

In C++, for instance, you can define an array whose size is a template argument (or a mathematical function on template args). Why not treat attribute names in the same way? (C++, regrettably, doesn't have a "symbol" type or any operations thereon, but you get the idea?)

You have a good eye; they

You have a good eye; they actually use a simple dependent type system to typecheck that field names are used properly.

Traits == Aspects?

It seems the problems it's trying to solve overlap with the ones AOP tries to solve. Is there any paper/article that compares the semantics and expressive power of two? I only found this on google: http://www.emn.fr/x-info/obasco/events/jfdlpa04/actes/denier.pdf

Lots of things overlap with AOP...

...as far as implementing domain-independent ("cross-cutting") concerns goes.

In this case, traits are being used for a sort of metaprogramming. The need to implement "properties" (private attributes with public getters-and setters) is a common thing.

Many a C++ programmer has done the same sort of thing crudely with a macro.

#define PROPERTY(type,name) \
private: type m_##name ; \
public: const type &get_##name () const { return m_##name ; } \
        void set_##name (const type &rhs) { m_##name = rhs; } 

class Bean 
{
    PROPERTY(int, foo);
    PROPERTY(double, bar);
    PROPERTY(string, baz);
};

Traits, aspects, macros, preprocessors, metaobject protocols, generic types, introspection and reflection, hook methods, monads, and even good old eval() are all means of metaprogramming, among other things. Not to mention the sorts of code-generation tricks that many IDEs and programming environments provide.

Many of these things are also useful for domain-specific programming. One thing about aspects that's either intriguing or disappointing--is that there doesn't seem to be much discussion of how they can help the application programmer (other than by abstracting away domain-independent concerns).

Traits == Aspects?

Traits and AOP augment the traditional OO paradigm with new modular constructs. Their goal is to increase reuse and maintenance in Software Engineering by defining new programming language constructs. Despite a similar goal, their way to expressing modularity is rather different.

Traits focus on structural reflection (a trait is a group of methods), whereas AOP focuses on behavioural reflection (an aspect is a set of code triggered before (or after) "base" methods). Although they may be interchangeable in some particular case, they completely differ on expressing "hooks" on the base system (composition operators vs. pointcut language description).

The mentioned paper employs the introduction of AspectJ (a.k.a inter-type) to have an aspect a group of methods in a trait-fashion. Such trait-flavoured aspect cannot be composed in the same way than a trait.

This sounds familiar somehow

To a Perl Library. No language extension required.

MOP

Couldn't this be done fairly easy in Common Lisp using MOP and macros?

Can you make it statically

Can you make it statically type safe in Common Lisp?

AFAIK type declarations are

AFAIK type declarations are optional in Common Lisp, and they are often used in order to get better performance. I don't know if for example declaring the type of every used variable would be enough for type safety (I am definitely not an expert in this field and I prefer not to engage in a discussion about it).

I just noticed that if I was facing the problems presented as example in the abstract (business objects with boilerplate code and so on), I would perfectly know what to use in CL: macros and MOP.

Yes, this paper deals with

Yes, this paper deals with metaprogramming facilities like what's available via MOP, except in the context of statically typed languages, where the various metaprogram extensions are safely composed to construct a program with no runtime errors.

[Edit: and no, declaring a type for every variable in Lisp would not be enough to recover the safety properties guaranteed by the type system in the paper. There are many threads on this site describing type systems if you're interested in seeing how powerful typing can really be.]

So where do you get the

So where do you get the statically typed database?

Most databases are strongly

Most databases are strongly typed as it is (albeit often clumsily), the rest's essentially another instance of dynamic linking. Or is it the initial dataset you're worried about?

It's that you've got two

It's that you've got two typed systems with only the loosest of bindings between them. Whereas the type of a function is usually well defined by what it does, the type of a database is subject to the whims of ALTER TABLE. Now a JIT system that dynamically type checks on connection to the database would be really useful.

You don't even need JIT -

You don't even need JIT - you just need sufficient introspection to know what types you're looking for.