Search code examples
cyclejs

Components, Isolate function, and 'referential transparency'


I have a (rather philosophical) question which refers to cyclejs components : Is isolate() referentially transparent?.

Looking at the simplified code, reproduced thereafter, I could not discriminate any source of 'impurity'. Is that because the not simplified code introduces it, or because the function would return two different objects with two different references?

In that case, would not those two objects have the same behaviour (i.e. listening and reacting to the same events on the same targets, and producing different vTree$ but which encapsulate exactly the same sequence?). And if that is so, aren't those two objects essentially the same, i.e. replacing one by the other anywhere in the program should not change anything? Which means isolate is referentially transparent? Where did I go wrong?

Actually if both calls returns different objects which cannot be substituted, how do those objects differ?

function isolate(Component, scope) {
  return function IsolatedComponent(sources) {
    const {isolateSource, isolateSink} = sources.DOM;
    const isolatedDOMSource = isolateSource(sources.DOM, scope);
    const sinks = Component({DOM: isolatedDOMSource});
    const isolatedDOMSink = isolateSink(sinks.DOM, scope);
    return {
      DOM: isolatedDOMSink
    };
  };
}

Solution

  • I could not discriminate any source of 'impurity'. Is that because the not simplified code introduces it, or because the function would return two different objects with two different references?

    The simplified code does not introduce impurity. The impurity comes from the fact that the parameter scope defaults to newScope() if it is not specified. The actual implementation of isolate() has:

    function isolate(dataflowComponent, scope = newScope()) {
      // ...
    }
    

    Where newScope() is:

    let counter = 0
    
    function newScope() {
      return `cycle${++counter}`
    }
    

    Meaning, if the scope is not given as argument, it defaults to the next value of a hidden global counter which is incremented every time isolate() is called.

    In conclusion, isolate(component, scope) is referentially transparent because we give the scope, but isolate(component) is not.