The Java Syntactic Extender - Examples

How to run the examples

Once you have installed Ant, open a command prompt in the examples directory, and type

ant
	

to build, and run the tests. It may be useful to look in the generated src directory to see the macro expansions.

A discussion of each example

when

The when macro is probably the simplest macro you can write. It is like a limited if with no else blocks. The idea is that code like

when (condition) {
  doSomething();
}
    

is preprocessed by JSE to the Java source

if (condition) {
  doSomething();
}
    

This is achieved by writing a when macro like this:

public syntax when {
  case #{
    when (?exp:expression)
      ?stmt:statement
  }:
  return #{
    if (?exp) {
      ?stmt
    }
  };
}
    

The case statement can be thought of as a generalised Java switch/case for pattern matching.

unless

In the same vein consider the unless macro, which is the inverse of when. This

unless (condition) {
  doSomething();
}
    

expands to

if (!(condition)) {
  doSomething();
}
    

Note that this time, the macro uses the expression ?:expression rather than ?expr:expression since the variable name defaults to the constraint name - so I can refer to ?expression in the return template.

using

The using macro allows you to dispense with ungainly finally blocks that call close() on a resource. That is,

using (Reader r = new BufferedReader(new FileReader(filename))) {
  doSomething(r.readLine());
}
    

is equivalent to:

{
  Reader r = null;
  try {
    r = new BufferedReader(new FileReader(filename));
    doSomething(r.readLine());
  } finally {
    if (r != null) {
      r.close();
    }
  }
}
    

Notice how much shorter the code with the macro call is.

foreach

The foreach macro is more complicated. Code like:

List l = ...
foreach (String s in l) {
  doSomething(s);
}
    

expands to:

List l = ...
for(java.util.Iterator i = l.iterator(); i.hasNext(); ) { 
  String s = (String) i.next();
  doSomething(s);
}
    

This example demonstrates the problem of variable capture: if the expansion is as shown above, then a nested foreach block will create a name clash for the local variable i. When hygiene is implemented in JSE, the preprocessor will take care of this clash by carefully renaming all local variables. Until then, you need to do the renaming yourself, using the method genSym (generate symbol) on the IdentifierFragment class.

assert

The assert macro provides a facility very like the facility introduced in Java 1.4. The differences are only in syntax, and the granularity of switching assertions on or off, the version presented here only allows assertions to be either all on or all off. Code like:

assert(x == y, "x: " + x + ", y: " + y)
    

expands to (see the assertions spec above for details of why this particular expansion is used):

do {
  if (!(examples.AssertionsStatus.ASSERTIONS_DISABLED || (x == y)))
    throw new examples.AssertionError("x: " + x + ", y: " + y);
} while(false);  
    

This example demonstrates the use of matching multiple patterns.

property

The property macro allows you to specify JavaBeans properties. Code like:

class Bean implements Serializable {
  public property String firstName = "Tom";
}
    

expands to:

class Bean implements Serializable { 
  private String firstName = "Tom";
  public String getFirstName () { return firstName ; }
  public void setFirstName (String x) { this.firstName = x ; }
} 
    

It would be simple to extend the example to support read-only and write-only properties.

enum

The enum macro provides a simple facility for enumerated types. Typical usage:

public enum Suit clubs, diamonds, hearts, spades;
    

This will create a class called Suit that has the enumerated constants clubs, diamonds, hearts, and spades each of type Suit. All generated enumerated type classes are Serializable and Comparable.

The facility shown here is simpler than the one proposed by Sun for introduction into Java 1.5. The major enhancements are the ability to add arbitrary fields and methods to an enum class, and the ability make the enum type implement arbitrary interfaces. Also, the Sun proposal extends the switch statement to allow switching on enumerated types - something we can not achieve using JSE. (However, switch is best replaced with method dispatching on the enum.)