Apr 01 2008

Nu Language Event Dispatcher

Nu is an interpreted object oriented language built on top of Objective C, with its syntax and several of its mechanics coming from Lisp, whilst being inspired by Ruby's philosophy.

The Event Dispatcher example is one of my favorite when trying out a new language. I choose it because it's representative of a number of programming language core topics such as lists, maps, closures, OO, etc.

I recently spent a short while porting the IO Language Event Dispatcher example in Nu and will be going over my experiment in this article.

Bellow is the code for the EventDispatcher class.

(class EventDispatcher is NSObject	
  (- (id) initialize is
    (set @listeners (dict))

  (- (void) subscribe:(id)event callback:(id)callback is
    (unless (@listeners objectForKey:event)
      (@listeners setObject:(array) forKey:event))
      ((@listeners objectForKey:event) << callback))

  (- (void) notify:(id)event withArgs:(id)args is
    ((@listeners objectForKey:event) each: (do 
      (callback) (callback args)))))

There are two prominent methods in this class, namely subscribe and notify.

The subscribe method takes two arguments, the event we're subscribing to and a callback to be invoked every time the specified event takes place. The @listeners dictionary is constructed using the dict directive, which is shorthand for creating an NSCFDictionary instance. For each event, we maintain an array of callbacks. Like dict, array is available for conveniently creating NSCFArray instances.

Whenever notify is invoked with an event and the relevant arguments, we iterate invoking any callbacks registered for the given event, passing the provided arguments to each.

There are two ways that I know of that will allow classes to act as event dispatchers, inheritance being the first.

(class Factory is EventDispatcher

  (- (void) produce:(id)color is
    (puts "#{color} product produced")
    (self notify:"new product" withArgs:color)))

Here, we create a Factory class which extends EventDispatcher and we define a produce method which notifies listeners that have subscribed to the "new product" event.

Composition is the second, and my preferred, option.

(class Factory is NSObject

  (- (void) produce:(id)color is
    (puts "#{color} product produced")
    (self notify:"new product" withArgs:color)))

(Factory include:EventDispatcher)

Classes in Nu can be used in a manner similar to that of Module mix-ins in Ruby. Every object in Nu has an include method which will make a class's instance methods available in another class. The advantage here is that we didn't have to change Factory's inheritance tree.

Following is a potential event listener that subscribes to the "new product" event and prints out a message every time the event is fired.

(class ProductWatcher is NSObject
  (- (id) watch is
    (factory subscribe:"new product" callback:(do (color) 
      (puts "I see a #{color} product")))))

To run the example, we can instantiate a Factory and a ProducWatcher and fire a few events.

(set factory ((Factory new) initialize))
((ProductWatcher new) watch)

(factory produce:"black")
(factory produce:"red")
(factory produce:"blue")

The results look like this:

black product produced
I see a black product
red product produced
I see a red product
blue product produced
I see a blue product

There are a lot of reasons as to why I have time for Nu, its combining 3 of my favorite languages not included, greatly simplifying Cocoa development for native Mac and iPhone applications and Objective C's excellent multi-core support to name but a few.