Evolutionary architecture and emergent design

Language, expressiveness, and design, Part 2

Continuing to explore how expressiveness in your code enables emergent design

Comments

Content series:

This content is part # of # in the series: Evolutionary architecture and emergent design

Stay tuned for additional content in this series.

This content is part of the series:Evolutionary architecture and emergent design

Stay tuned for additional content in this series.

This is the second part of a two-part article illustrating how the expressiveness of computer languages helps with emergent design by allowing you to concentrate more on essence than on ceremony. A chasm between intent and result is characteristic of many decades-old languages (including the Java™ language), adding needless ceremony to problem solving. More-expressive languages make it easier to find idiomatic patterns because the code contains less noise. This expressiveness is a hallmark of modern languages like Groovy and Scala; older but more-expressive languages like Ruby, of which JRuby is the JVM variant; or reimagined older languages like Clojure, the modern Lisp on the JVM (see Related topics). In this article, I continue the demonstration I began in Part 1— implementing the traditional Gang of Four patterns from the Design Patterns book in more-expressive languages.

The Decorator pattern

The Gang of Four book defines the Decorator pattern as:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

If you've ever used the java.io.* packages, you are intimately aware of the Decorator pattern. Apparently, the designers of the I/O libraries read the Decorator section of the Gang of Four book and really took it to heart! First, I'll show a traditional implementation of the Decorator pattern in Groovy, then make it more dynamic in subsequent examples.

Traditional decorator

Listing 1 shows a Logger class along with a couple of decorators for it ( TimeStampingLogger and UpperLogger ) all implemented in Groovy:

Listing 1. Logger and two decorators
class Logger {
    def log(String message) {
        println message
    }
}

class TimeStampingLogger extends Logger {
    private Logger logger

    TimeStampingLogger(logger) {
        this.logger = logger
    }

    def log(String message) {
        def now = Calendar.instance
        logger.log("$now.time: $message")
    }
}

class UpperLogger extends Logger {
    private Logger logger

    UpperLogger(logger) {
        this.logger = logger
    }

    def log(String message) {
        logger.log(message.toUpperCase())
    }
}

Logger is a simple logger that writes the log message to the console. TimeStampingLogger adds a time stamp via decoration, and UpperLogger changes the log message to uppercase. To use either of these decorators, you wrap a Logger instance with the appropriate decorator, as shown in Listing 2:

Listing 2. Using decorators to wrap a logger
def logger = new UpperLogger(
    new TimeStampingLogger(
        new Logger()))

logger.log("Groovy Rocks")

The output from Listing 2 shows a log message with a time stamp in uppercase:

Tue May 22 07:13:50 EST 2007: GROOVY ROCKS

So far, the Groovy implementation is only thing unusual about this decorator. But I can make a decorator without adding the extra structure of a class-based approach.

Decoration in place

Traditional design patterns from the Gang of Four book assume that the solution to every problem requires building more classes. However, modern languages on the JVM have other facilities, such as open classes, which allow you to reopen existing classes and add new methods to them without requiring subclassing. This is particularly handy when you need to change the behavior of a class that's used by part of the infrastructure (for example, the collections API) that requires a certain class. You can modify an existing class, pass it as a parameter, and take advantage of the API without requiring the base API to declare an abstract class or interface. Open classes also allow you to make modifications "in place" without the need to subclass.

However, changing the entire class definition sounds scary: you might not want to make pervasive changes throughout the entire universe. Fortunately, both Groovy and Ruby allow you to add new methods to single instances of classes. In other words, you can add a new method just to an instance of Logger without affecting all other instances of it. Listing 3 shows the use of the ExpandoMetaClass in Groovy to overwrite the log() method on a single instance of Logger:

Listing 3. Overriding the log() method on an instance of Logger
def logger = new Logger()
logger.metaClass.log = { String m ->
  println m.toUpperCase()
}

logger.log "this log message brought to you in upper case"

Once you understand how the mechanism works, reading this code is much simpler than reading the corresponding code that uses additional classes. All the relevant decoration code appears in one place rather than scattered around in several files (because in the Java language, each public class must reside in its own file).

This same capability exists in Ruby using a Ruby feature known variously as singleton method (which is a confusing name because singleton is so overloaded) or the eigenclass. The same code implemented in JRuby appears in Listing 4:

Listing 4. In-place decoration using Ruby's eigenclass
class Logger
  def log(msg)
    puts msg
  end
end

l = Logger.new
def l.log m
  puts m.upcase
end

l.log "this log message brought to you in upper case"

The Ruby version doesn't use an extra facility such as ExpandoMeta Class. In Ruby, you can define a method inline for a particular instance by putting the variable name at the beginning of the method declaration. Ruby has great syntactic flexibility, imposing fewer rules about when and where you can define methods.

This facility works for built-in Java classes as well. For example, the ArrayList class should have been defined with a first() and last() method, but alas it did not. However, it's easy enough to add those methods in Groovy, as shown in Listing 5:

Listing 5. Groovy's addition of a first() and last() method for ArrayList
ArrayList.metaClass.getFirst {
  delegate.size > 0 ? get(0) : null
}

ArrayList.metaClass.getLast {
  delegate.size > 0 ? get(delegate.size - 1) : null
}

ArrayList l = new ArrayList()
l << 1 << 2 << 3
println l.first
println l.last

ArrayList emptyList = new ArrayList()
println emptyList.first
println emptyList.last

The ExpandoMetaClass allows you to define new properties on classes (using the familiar Java get/set naming pattern). Once you have defined the new properties on the class, you can invoke them just as you would normal properties.

And you can do the same in JRuby, as shown in Listing 6, using the existing JDK classes:

Listing 6. Adding methods to ArrayList using JRuby
require 'java'
include_class 'java.util.ArrayList'

class ArrayList
  def first
    size != 0 ? get(0) : nil
  end

  def last
    size != 0 ? get(size - 1) : nil
  end
end


list = ArrayList.new
l << 1 << 2 << 3
puts list.first
puts list.last

empty_list = ArrayList.new
puts empty_list.first
puts empty_list.last

Don't fall into the trap of thinking that the solution to every problem requires more classes. Metaprogramming often provides much cleaner solutions to problems.

Decorator with invocation hooks

Sometimes you need decoration that covers more than just a few classes. For example, you might want to decorate all your database operations with transactional controls. Creating a simple, traditional decorator for each case is too cumbersome, and it would add so much syntax to your code that it would be hard to determine which unit of work you're aiming for.

Consider the decorator shown in Listing 7, implemented in Groovy:

Listing 7. GenericLowerDecorator in Groovy
class GenericLowerDecorator {
    private delegate

    GenericLowerDecorator(delegate) {
        this.delegate = delegate
    }

    def invokeMethod(String name, args) {
        def newargs = args.collect{ arg ->
            if (arg instanceof String) return arg.toLowerCase()
            else return arg
        }
        delegate.invokeMethod(name, newargs)
    }
}

The GenericLowerDecorator class acts as a universal decorator to force all string-based parameters into lowercase. It does so by using a hook method. When you invoke this decorator, you wrap it around any instance. The invokeMethod() method intercepts all method calls to this class, allowing you to perform whatever actions you like. In this case, I intercept each method call and go through all the method parameters. If any of the parameters are of type String, I add the lowercase version of it to a new arguments list, and leave the other arguments intact. At the end of the hook method, I invoke the original method call on the decorated object using my new argument list. This decorator converts all string parameters to lowercase, regardless of the method or its parameters. Listing 8 shows an example of its use, wrapping one of the loggers from Listing 1:

Listing 8. Using GenericLowerDecorator on a Logger
logger = new GenericLowerDecorator(
    new TimeStampingLogger(
        new Logger()))

logger.log('IMPORTANT Message')

Any method called with this decorator uses only lowercase strings:

Tue May 22 07:27:18 EST 2007: important message

Notice that the time stamp isn't put in lowercase but the String parameter is. This is possible in the Java language but very difficult. In fact, using aspects (via AspectJ, for example) is the only way to achieve this effect in the Java language (see Related topics). To get this type of decorator, you must switch to another language with its own compiler and set up postprocessing for your Java code. While not impossible, this process is so cumbersome that you'll never bother.

The Adaptor pattern

The Gang of Four book describes the Adaptor pattern as:

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

If you've ever used event handlers in Swing, you have intimate knowledge of the Adaptor pattern. It is used to create adaptor classes around the event-handling interfaces that contain more than one method so that you don't need to create your own class, implement the interface, and include lots of empty methods. The Swing adaptors allow you to subclass the adaptor and just override the methods you need to handle for the event.

Adaptation in Groovy

Ultimately, though, the Adaptor pattern tries to answer the question: "Can I get this square peg to fit into this round hole?" That's the problem I'm going to solve, with two different implementations, each highlighting expressiveness in the language. The first implementation uses Groovy; the three classes and one interface of interest appear in Listing 9:

Listing 9. Square pegs and round holes
interface RoundThing {
    def getRadius()
}

class SquarePeg {
    def width
}

class RoundPeg {
    def radius
}

class RoundHole {
    def radius

    def pegFits(peg) {
        peg.radius <= radius
    }

    String toString() { "RoundHole with radius $radius" }
}

A traditional adaptor implementation would create a SquarePegAdaptor class, wrapping the square peg and implementing a getRadius() method expected by the pegFits() method of RoundHole. However, Groovy allows me to bypass the extra structure of an additional class, defining my adaptor directly inline as shown in Listing 10:

Listing 10. Testing the inline adaptor
@Test void pegs_and_holes() {
  def adapter = { p ->
    [getRadius:{Math.sqrt(
      ((p.width/2) ** 2)*2)}] as RoundThing
  }
  def hole = new RoundHole(radius:4.0)
  (4..7).each { w ->
    def peg = new SquarePeg(width:w)
      if (w < 6)
        assertTrue hole.pegFits(adapter(peg))
      else
        assertFalse hole.pegFits(adapter(peg))
  }
}

The adapter definition looks a bit strange but encapsulates a lot of functionality. I define adaptor as a code block (delimited by { in Groovy). Inside the code block, I create a hash, where the key is the name of a property (getRadius()) and the value is a code block that implements the functionality I require of my adapter. The as operator in Groovy performs magic. When I use the as operator on a code block, Groovy creates a new class that implements the RoundThing interface; method invocations on that class perform a lookup in the hash, match the method name to the key value, and execute the corresponding code block. The end result is an extremely lightweight adapter class that implements the functionality required by the RoundThing interface.

Although the ultimate implementation at the class level looks the same as the traditional approach, the code (once you know Groovy) is much easier to read and understand. Groovy allows you to create lightweight wrapper classes around interfaces for just this situation.

Adaptor pattern in JRuby

What if you didn't want to create an extra class at all for your adapter? Both Groovy and Ruby support open classes, allowing you to add the required method directly to the class in question. The implementation of square pegs and round holes in Ruby (via JRuby) appears in Listing 11:

Listing 11. Open-class adaptor in Ruby
class SquarePeg
  attr_reader :width

  def initialize(width)
    @width = width
  end
end

class SquarePeg
  def radius
    Math.sqrt(((@width/2) ** 2) * 2 )
  end
end

class RoundPeg
  attr_reader :radius

  def initialize(radius)
      @radius = radius
  end

  def width
    @radius * @radius
  end
end

class RoundHole
  attr_reader :radius

  def initialize(r)
    @radius = r
  end

  def peg_fits?( peg )
    peg.radius <= radius
  end
end

The second definition of the SquarePeg class in Listing 11 isn't a mistake: Ruby's open-class syntax looks like a regular class definition. When you use a class name, Ruby checks to see if it has already loaded a class from the classpath by that same name and, if it has, the second occurrence reopens the class. Of course, in this case, I could have just added the radius() method directly to the class, but I'm assuming that the original SquarePeg class predates this code. Listing 12 shows the unit test for the open-class adaptor:

Listing 12. Testing the open-class adaptor
def test_open_class_pegs
  hole = RoundHole.new( 4.0 )
  4.upto(7) do |i|
    peg = SquarePeg.new(i.to_f)
    if (i < 6)
      assert hole.peg_fits?(peg)
    else
      assert ! hole.peg_fits?(peg)
    end
  end
end

In this case, I can call the radius method directly on the SquarePeg class because it now has a radius method. Adding a method via an open class entirely removes the need for a separate adaptor class, whether written by hand or automatically generated. However, a potential problem does exist with this code: what if the SquarePeg class already had a radius method that has nothing to do with round holes? Using the open class will overwrite that original class, causing undesirable behavior.

That's where the power of a truly expressive language arrives in full force. Consider the Ruby code in Listing 13:

Listing 13. Interface switching
class SquarePeg
  include InterfaceSwitching

  def radius
    @width
  end

  def_interface :square, :radius

  def radius
    Math.sqrt(((@width/2) ** 2) * 2)
  end

  def_interface :holes, :radius

  def initialize(width)
    set_interface :square
    @width = width
  end
end

This code is literally impossible to write in the Java language or Groovy. Notice that I have defined two methods with the name radius. In Groovy, the compiler won't compile this code. However, Ruby (and therefore JRuby) is an interpreted language, allowing you to execute code at interpretation time. You hear some Rubyists refer to constructs in Ruby as "first class citizens," meaning that all parts of the language are available at all times. The magic here lies with the (keyword-like) def_interface method call. This is a metaprogramming method defined on the Class class that executes at interpretation time. This code allows you to define a particular interface for a method, allowing that method to exist only within a certain scope. The scope is defined by the with_interface method call, as shown in Listing 14:

Listing 14. Testing interface switching
def test_pegs_switching
  hole = RoundHole.new( 4.0 )
  4.upto(7) do |i|
    peg = SquarePeg.new(i)
    peg.with_interface(:holes) do
      if (i < 6)
        assert hole.peg_fits?(peg)
      else
        assert ! hole.peg_fits?(peg)
      end
    end
  end
end

Within the scope of the with_interface block, the radius method defined with that interface name exists and can be called. The code in Listing 15 to make this work is surprisingly small (but somewhat dense). It is shown here for context; most of it is semi-advanced Ruby metaprogramming so I won't discuss it in detail.

Listing 15. Interface-switching magic
class Class
  def def_interface(interface, *syms)
    @__interface__ = {}
    a = (@__interface__[interface] = [])
    syms.each do |s|
      a << s unless a.include? s
      alias_method "__#{s}_#{interface}__".intern, s
      remove_method s
    end
  end
end


module InterfaceSwitching
  def set_interface(interface)
    unless self.class.instance_eval{ @__interface__[interface] }
      raise "Interface for #{self.inspect} not understood."
    end
    i_hash = self.class.instance_eval "@__interface__[interface]"
    i_hash.each do |meth|
      class << self; self end.class_eval <<-EOF
        def #{meth}(*args, &block)
                send(:__#{meth}_#{interface}__, *args, &block)
        end
      EOF
    end
    @__interface__ = interface
  end

  def with_interface(interface)
    oldinterface = @__interface__
    set_interface(interface)
    begin
      yield self
    ensure
      set_interface(oldinterface)
    end
  end
end

The interesting code in Listing 15 appears at the end of the open-class Class definition, where the named method is given another name (based on the interface) and then programmatically removed from the class. More interesting code appears in the InterfaceSwitching mix-in: the set_interface method redefines the original (renamed) method for the scope of the block created within the with_interface method. Ruby's version of a finally block is the ensure block at the end.

The point of this exercise isn't necessarily a deep dive into voodoo metaprogramming in Ruby, but rather to demonstrate what is possible in highly expressive languages. Interpreted languages always have an advantage over compiled languages because they can execute code at times that compiled languages can't. In fact, Groovy has introduced a compile-time metaprogramming mechanism called AST Transformations, whereby you can write code to interface with the compiler (see Related topics).

Summary

So what does all this prove? In languages, expressiveness equals power. You don't see many of these techniques in the Java language, even though they are technically possible through aspects and bytecode generation using tools such as Javassist (see Related topics). However, solving problems using those mechanisms is so cumbersome that no one bothers. That attitude affects idiomatic patterns as well. Even if you can see patterns particular to your application, if the way to harvest them is too difficult, you won't bother, thereby building up needless technical debt on your project. Expressiveness matters in computer languages ... a lot!


Downloadable resources


Related topics

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java development
ArticleID=424715
ArticleTitle=Evolutionary architecture and emergent design: Language, expressiveness, and design, Part 2
publish-date=09012009