Decorators in TIScript, fun of UI programming is back.

January 26, 2009

Filed under: Sciter,Script — Andrew @ 10:21 pm

Latest builds of the Sciter have decorators implemented. My implementation of decorators ideologically derived from the same decorator feature in Python of Guido van Rossum.

Decorators is a meta/macro-programming feature that allows to transform or update function or class defined in source code.

Here is an example: say we are designing some dialog with various input elements and buttons. Usually code behind such dialogs is a collection of simple “if-we’ve-got-some-event-here-then-update-state-over-there” blocks. First part (if-we’ve-got-some-event-here…) of the task is repeating again and again. The desire is to make it as short and clear as possible. With decorators this could be written as:

@when Event.BUTTON_CLICK @on "button#add-new" :
   {
      this.select("#list").insert( new Element( "option", "new item") );
   }
@when Event.SELECT_SELECTION_CHANGED @on "select#list" :
   {
      this.select("#delete-current").state.enabled = true;
   }
...

This makes such sequence of blocks to look more like a table of records: when (event) on (where) (then do this). That is more declarative approach if you wish. This code is better maintainable I think.

@when and @on here are decorators of anonymous function that follow them. ( Sequence :{ ... } declares anonymous function in TIScript ).

Decorator in TIScript is an ordinary function with the name starting ‘@’ and at least one parameter. This first parameter is a reference to function that is being decorated. Decorator-function in its turn can dynamically create another function that will wrap call of original function.

Here is how our @when and @on decorators might look like:

// decorator '@when' - filters event by type 
function @when(func, evtType)
    {
      return self.onControlEvent = function(evt)
         {
           if( evt.type == evtType) 
              return func.call(this,evt);
         }
    }

// decorator '@on' - filters evt.target by the selector
function @on(func, selector)
    {
      return function(evt)
      {
        if( evt.target.match(selector) ) // if target element matches 
          return func.call(this,evt);       // the selector call the func. 
      }
    }

Chain of decoratorsAs you may see both decorators simply create wrapper functions that filter the event using different criteria. Thus following statement:

@when Event.BUTTON_CLICK @on "button#add" :{...code...}

simply establishes chain of filters that ends up with the call of code that handles the event.

Syntax of decorators in TIScript is described here.