News

muvee Reveal - the latest incarnation of muvee's flagship product - has just been released on 11 June 2008! The behaviours of the 8 bundled styles are specified using muSE, in addition to all the styles developed for the now discontinued muvee autoProducer 6.1.

Wednesday, December 13, 2006

Exception mechanism

muSE had so far lacked the facility to raise exception conditions and handle them in code that's specified non-locally. One could conceivably use the call/cc construct to implement raising exceptions, but capturing a continuation to evaluate an expression that often won't invoke the continuation turns out to be expensive in terms of memory - capturing a continuation copies the stack in muSE.
As of version 73 in the processes branch, a simple exception raising and handling mechanism has been added to muSE. There are two new primitives involved -

(raise ...args...)


The raise primitive is used to flag an exceptional condition and results in all the established handlers being tried one by one until one of them can be found to handle the condition. A handler (which is a function) is taken to accept an exception for handling if its argument pattern matches the pattern of arguments to the raise expression that raised the exception.



(try expr handler1 handler2...)


The try block wraps the expr with handlers that get tried when any sub-expression of expr raises an exception.


Any muSE object can be used in the place of a handler. If the object is a function, then its arguments have to pattern match against the exception raised in order for its body to be evaluated as the result of its try block. If the object is not a function, its value is used as the result of the try expression as is. For example -


(try (if (< a b)
(- b a)
(raise 'NotInOrder a b))
0)
will evaluate too 0 if a >= b.


A function used as a handler needs to have its arguments in a special order -

  1. The first argument to the handler is an exception object.

  2. The remaining arguments are the same list of values passed to the raise expression that raised the exception.


For example -
(fn (ex 'NotInOrder x y) ...)
can be the signature of a handler that handles the 'NotInOrder exception raised by the previous example. The ex argument's sole purpose is to let you resume the computation from the raise expression with a new valid value as the result of the raise. The ex object is actually a (cheaper than call/cc) continuation that you can invoke with a single argument that will resume the computation in such a manner. To expand on the previous example,



(try
(do (write "Difference = "
(if (< a b)
(- b a)
(raise 'NotInOrder a b)))
(write "Product = " (* a b)))

(fn (ex 'NotInOrder x y)
(ex (- x y))))

In the above form, the exception condition is corrected by reversing the arguments of the subtraction operation. If the handler did not invoke the exception object to resume the computation, its result value is used as the result value of the try block. Trivial example, yes, but serves to illustrate the point.

No comments: