Skip navigation

So perhaps the most important set of features provided by Fera are those which together provide a cohesive aspect-oriented programming framework. This is still very much a work in progress (I’m in the process of defining and implementing it in the reference compiler). As far as I can find, there are no other languages for .NET which integrate aspect-oriented programming syntactically. There are many aspect-oriented frameworks but none have come close to standardization and I think cross-language AOP won’t be feasible until Microsoft, Mono or some other big player in the CLI world steps up and creates something everyone can agree on. So due to this limitation, Fera can only use aspects written in Fera.

The model chosen is similar to AspectJ and other AOP languages. You define member matching patterns (called ‘pointcuts’) and advice in the form of join methods or error conditions within special types called ‘aspects’. Aspect classes can inherit normal classes or aspects (but classes cannot inherit aspects). Aspects cannot be instantiated directly, as they are singleton classes. All aspects have an Instance property which retrieves this singleton instance.

All pointcuts and advice are named like any other CIL member. Pointcuts can match methods, nested join points in methods, fields, indexers, properties, events and other pointcuts. Join methods reference these pointcuts (or create them anonymously), and attach a join target (one of ‘in’, ‘before’ or ‘after’).

Methods can also define nested join points with the ‘join’ keyword, which can be matched by pointcuts like anything else. These join points have signatures just like methods, and data is passed from the method to the join point for consumption by join advice. Example:

public void Blah ():
    join Inner (int)
{
   join Inner (3);
}

A pointcut which matches the Inner nested point looks like this:

pointcut BlahInner {
   method void %.Blah().Inner (int);
}

The % character is used as a wildcard within pointcut match clauses. When targetting properties/fields/events with a pointcut, you can match individual events for those types. Field and property accepts ‘get’ and ‘set’, events accept add/remove. The parameters specified in method/indexer matches have special properties. You can use the ‘…’ symbol as a parameter to specify that there is zero or more arbitrary parameters. You can only have one ‘…’ in a pointcut match definition (this isn’t an arbitrary limitation, parameter matching becomes very ambiguous when this is not the case). The same pattern matching is available for the types of the parameters, but parameters using type pattern matching cannot be captured within join advice.

A join advice definition looks like this:

join (int i):
   BlahInner (int i)
{
   // do something here
}

This particular join matches all items of the BlahInner pointcut, adding a more specific version of the parameter list which overrides the one described within the BlahInner pointcut. I say “more specific” intentionally, you cannot attach an overridden parameter list which would not have been matched by the original pointcut. As you see, a name is attached to the int parameter specified in the BlahInner pointcut. This is called parameter capturing. The name (which is the same as the real parameter ‘int i’) is linked so that calls to the join from items matching BlahInner are provided with the method’s first int argument.

You can also define error/warning advice which causes compile-time errors/warnings respectively when a pointcut matches something. It is also possible to filter these errors based on the caller information.

All types/members created for aspect-related stuff is marked with attributes from the Fera.Runtime.Aspects namespace. Aspect classes are marked with AspectAttribute, Pointcuts are generated as constant null CIL fields with PointcutAttribute and a set of PointcutMatchAttributes. Join methods become normal methods with JoinAdviceAttribute and a set of PointcutMatchAttributes.

I’ve got the syntactic elements defined within the Fera grammar, and the IR representation contains the proper structures to support them. Next I need to work on the resolution of name patterns as well as resolving non-pattern builtin types into their fully qualified equivalents. Then I must create the aspect application code, which, to do efficiently, will probably require having a list of the aspects available for when each method is compiled. (that way you don’t start with an join() method and then search the entire type system to find items which match it, the opposite is much more efficient). More info later.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: