The most interesting features we implemented using macros

1. Intro

This page is dedicated to the features of Nemerle and its library, which have been implemented using our meta-programming facilities.

Understanding how macros work is not necessary for using any of them. It would be useful only for knowing that those examples are just a tip of an iceberg called meta-programming and that you can easily implement even nicer things.

2. Design by Contract

Languages like Eiffel or Spec# incorporate a methodology called Design by Contract to reason about programs, libraries, methods. It allows to write more secure and correct software and specify its behavior.

The language following this design must support writing explicit requirements about values on which a program operates. It contains:

We are currently on the way to add an ability to define most of those features to Nemerle. In the following subsections we present their current state, design and plans for the future.

2.1. Preconditions - Requires attribute

Preconditions of a method (conditions that need to be satisfied before the method is called) can be specified using the Requires attribute.


class String {
  [Requires (startIdx >= 0 && startIdx <= this.Length)]
  public Substring (startIdx : int) : string 
  { ... }
}

Using this attribute we can add an arbitrary assertion, keeping the body of the method clean and verbose. The compiler automatically adds runtime checks at the beginning of the method. If the condition is violated, then an AssertionException is being thrown with an appropriate message containing this expression.

Requires and other attributes can occur many times before a single method. They can be also defined directly on parameters.

ConnectTrees ([Requires (!tree1.Cyclic ())] tree1 : Graph,
              [Requires (!tree2.Cyclic ())] tree2 : Graph, 
              e : Edge) : Graph 
{ ... }

2.2. Postconditions - Ensures attribute

Following the same design, we can define postconditions which the method must satisfy. This is an assertion that must be true after the execution of the method. If the method returns a value, then a symbol value is available inside the expression stating an assertion.

class LinkedList {
  [Ensures (IsEmpty ())]
  public Clear () : void
  { ... }

  [Ensures (value >= 0)]
  public Length () : int
  { ... }
}

2.3. Class invariants - Invariant attribute

An even more powerful feature is to give a condition, which must be true all the time during the execution of a program. We can attach invariant to any class by writing Invariant attribute before its definition.


[Invariant (position >= 0 && position <= arr.Length)]
class Vector <T> {
  private mutable position : int = 0;
  private arr : array <T> = array [];

  public push_back (x : T) : void 
  { ... }

This way we can control that our object is in some set of valid states.

This naturally brings the problem with changing variables, which are dependent on each other in invariant. Suppose we have an assertion x == y + 5 and we cannot change any of the variables. Thus, we need a mechanism for making transactions, within which invariants are temporarily ''turned off''.

We follow the design of Spec# and add a special construct to expose the object to changes.

expose (this) {
  x += 3;
  y += 3;
}

expose takes reference to the object to be exposed and executes the given code.

In the matter of fact, invariants are not checked all the time during execution. It would be too expensive to validate them at any assignment or call to external function. We again follow design of Spec# and run assertions at the end of expose blocks and after execution of all public methods.

2.4. Future work

There are few more things which we want to implement in more or less distant future:

3. Compile-time validation of embedded SQL queries

As for now see this.

4. Aspects-Oriented programming

As for now see this.