0

Should JavaScript have enough expressivity to perform 'contextual' polymorphism?

What I mean is to have an object that exposes different interfaces depending on its internal state, where this mechanism would be implemented using module pattern, method chaining and closures.

For instance: suppose a Finite State Machine:

// definition time
let m = machines_module.factory('machine-01', options);

m.onsuccess(function() { console.log(''done !''); });
m.onfailure(function() { console.log(''error !''); });

m.def('state-1')
  .inital()
  .when('event-a', 'state-2')
  .when('event-b', 'state-3');

m.def('state-2')
  .when('event-a', 'state-3');

m.def('state-3')
  .terminal()
  .when('event-b', 'state-2');
// etc... dozens of defs

// switch to run time
m.go('state-1');

// accept is only visible at run-time
m.accept('event-a');
m.accept('event-b');
// hundreds of transitions

// --> success  or failure

// switch back to def-time
m.halt();

By the way, object signature are context dependent. At definition time you cannot accept events and at runtime you cannot add new states.

Is this possible? I guess it's yes

Since I tested:

 let X = {
   abc : 123,
   del : function() {
     for(let prop in this) {
       delete this[prop];
     }
   },
   xyz : 'will be destroyed by del() method'
 };

which, surprisingly for me, worked... I could now implement the code below...

The idea is to port into ES6 the project:

https://github.com/hefeust/dexm

Which is my first implementation on a finite state machine with time-embedded ability (TEFSM).

I repeat; the basic idea is to offer access to several methods of an object, depending of its internal state (stopped or running), thus to enforce data protection and safety of use.

Here's the code:

'use strict';

// Inside a module pattern
class Utils {
  static eraseProps(obj) {
    console.log('   erase props');
    for(let prop in obj) {
      delete obj[prop];
    }
  };

  static cloneProps(fromObj, toObj) {
    console.log('   clone props');
    for(let prop in fromObj) {
      toObj[prop] = fromObj[prop];
    }
  }
}

class ContextualPolymorphic {
  constructor() {
    this.defs = new Map();
    this.state = false;
  };

  def(name, value) {
    this.defs.set(name, value);
  };

  list() {
    return this.defs.keys();
  };

  go() {
    this.state = true;
  };

  halt() {
    this.state = false;
  };

  defWrapper() {
    let self = this;

    return {
       go() {
         self.go();
         Utils.eraseProps(this);
         Utils.cloneProps(self.wrapper, this);
       },
       def(name) {
         self.def(name);
       }
    };
  };

  runWrapper() {
    let self = this;

    return {
       halt() {
         self.halt();
         Utils.eraseProps(this);
         Utils.cloneProps(self.wrapper, this);
       },
       list() {
         return self.list();
       }
    };
  };

  get wrapper() {
    if(this.state) {
      return this.runWrapper();
    } else {
      return this.defWrapper();
    }
  };
}

// module's factory method
let cp = new ContextualPolymorphic();

// we can solely access to "w",
// it s published outside the module
// w id public, cp is privatized
let w = cp.wrapper;

// tests
console.log('def phase');
console.log(w);
w.def('abc');
w.go();

console.log('run phase');
console.log(w);
w.list();
w.halt();

console.log('ready for new def-phase');
console.log(w);

So, what are your feelings?

Is it possible to write the mechanism of contextual polymorphism simpler? without delete and cloning props into the wrapper getters?

3
  • I'd personally implement a state flag (if you really want to be strict do it with closures instead of a property) and have functions return immediately (or throw errors if you're sadistic) when called in the wrong state. This can be implemented in almost any language Commented Nov 2, 2016 at 16:08
  • It's a trial... but your idea sounds good Commented Nov 3, 2016 at 7:16
  • Possible duplicate of JavaScript pattern for multiple constructors Commented May 16, 2017 at 21:32

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.