Agile software development using Kanban & Scrum. We code Flex & Ruby on Rails in Auckland, New Zealand.

  • Musings on AS4 - Part 1, Safe Navigation, Safe Exclusion

    So I had surgery 2 nights ago. Routine Gall bladder thing. But the pain killers, namely morphine, keep me awake, contrary to their typical side effects. This left me up all night, in a hospital room, with such a calm mind and strange thoughts, that my desires for Actionscript began to crystalise.

    These are meant to be idea’s to argue over, so please do comment.

    Safe Navigation

    Groovy’s Safe Navigation Operator is pretty straight forward:

    var a:String = b?.c?.e
    

    If b evaluates to null, a is null. Same for c.

    It’s wonderful. I really don’t think I need to use Null Objects as often as I do.

    Safe Exclusion

    “Alan Kay’s meaning of OOP” and ObjC’s message passing got me thinking about thorough bi-directional decoupling. In the vWork application code, we have a considerable number of modules, which use a notifier bus (Robotlegs Modular context) to pass messages between modules. To properly decouple ‘Module A’ from ‘Module B’, I ended up with something like:

    module.a.events.IRaiseThisEventOnTheBus
    module.b.events.IExpectThisEventToBeRaised
    

    or to be more concrete:

    module.map.workerSelectedEvent
    module.workerManager.selectWorkerEvent
    

    and then I have a ‘master’ module manage the coupling. It listens for ‘workerSelectedEvent’ and fires the selectWorkerEvent. Now neither module has an import from the other…

    The glue module still couples.

    And this is the rub. My master module (usually the application boot module) has knowledge (read: imports) of both modules. Thats not a truly decoupled program.

    Dynamic events

    So the obvious way to get true decoupling is to use untyped messages. Like ruby, or ObjC might do. It works because a module can dissapear, and the other ‘dependent’ module is just listening for a magic string or symbol that never arrives.

    I don’t like this approach, because I like type-safety.

    Type-Safe events can be missing

    My solution is to allow namespaces and classes to be missing. A kind of null-safety if you will. I can only describe it in code:

    Describe an event class:

    package module.map.events {
    
      import flash.events.*  
    
      public class WorkerSelectedEvent extends Event {
         ... event boilerplate ...
         public function get payload():TypeSafeThing {
           return _payload;
         }
      } 
    }
    

    And ‘Maybe’ consume it:

    package module.workerManager.config {
    
      use module.map.events.WorkerSelectedEvent;
      use module.map.TypeSafeThing; 
    
      public class Config {
        ... stuff ...
        public function configWorkerListener() {
          if (WorkerSelectedEvent is _UndefinedClass)
            return;
    
          bus.addEventListener(WorkerSelectedEvent.SELECTED, selectedHandler);
        }
      } 
    }
    

    Where ‘use’ is defined instead of ‘import’, the compiler will find the Class, but if it cannot, it will replace it with an instance of _UndefinedClass, which has no methods or behaviour, it’s just a marker.

    I would quickly replace EventDispatchers with something like Rob Penner’s signals (although I want to see c# style delegates, which I’ll cover in part 2). A signal/delegate message passing system could happily accept an _UndefinedDelegate and make most of this decoupling transparent.

    I suspect ‘use’ would be the defacto when specifying message classes/delegates.

    1. vworkdev posted this