Hi,

TLDR ==> The web needs a way to express executable code that does not rely on 
its parent context, is guaranteed to be side-effect-free, and can be executed 
safely anywhere (even in a different thread/worker/window/device, or as 
callback for browser code being executed while the DOM is not ready to be 
accessed)

 
It's been some time I've been working on this idea of a Closure-free, 
Serializable function. This kind of function would have no access to the parent 
closures they are defined in, and only limited (read-only) access to the 
enclosing environment (read-only Math, Object, Array, others...).
 
To the difference of other functions, those objects would not be affected by 
the JavaScript running elsewhere on the page, so in this closure-free function, 
Array.prototype.slice is guaranteed to be the native slice function, not some 
kind of polyfill or replaced function. 
 
|    function sort(array) as serializable {
|        Array.prototype.sort.call(array);
|    }
 
|    function sqrt(number) as serializable {
|        return Math.sqrt(number);
|    }
 
|    function __BAD_CODE__() as serializable {
|        return new XMLHttpRequest(); // xhr not defined in ES6
|    }
 
Trying to export a global variable or modify any of the host 
environment-defined objects would fail. 
 
|    function __BAD_CODE__(number) as serializable {
|        globalNumber = number; // cannot write into the global object
|    }

|    function __BAD_CODE__() as serializable {
|        Object.prototype.doSomething=function() {}; // cannot write into the 
native objects
|    }
 
It's also important to note that any Object or Array created inside this 
context will be passed to the calling context by deep-cloning (or by replacing 
the "safe" Math object by the host Math object of the calling code in the case 
of environmental objects). Objects that can't be cloned (non-serializable 
functions, for example) are just transformed into null. We could also maybe use 
the idea of a proxy though deep-cloning seems safer. 
 
This makes sure it's impossible to leak the "safe" objects to the calling 
context in any way (ie: the calling code can leak anything to the called code, 
but not the reverse).
     
|    var RealSin = Math.sin;
|    Math.sin=function() {};
|    
|    function giveMeMath() as serializable {
|        return [Math, Math.sin];
|    }
|    
|    var [m,s] = giveMeMath();
|    // s === RealSin
|    // m === Math
|    // m.sin !== RealSin
|    
|    // note that another possibility here
|    // would be to have giveMeMath return [null,null]
|    // (ie: consider host objects unserializable)
 
To be honest, those functions are not really meant to expose new objects: even 
if they need some internally, they should just keep them internally and avoid 
distributing them. The deep-cloning algorithm is just there for the cases where 
you want to return multiple values at the end of a function, or when you need 
an options object. 
 
Still, the fact they run in a "safe" environment makes them a good candidate 
for further optimization and inlining, so we may end up seeing codes written as 
serializable to benefit from performance boost and safety from external attacks.
 
|    function Point(x,y) as serializable {
|        x = +x; 
|        y = +y;
|        return { 
|            x:x, 
|            y:y, 
|            r: Math.sqrt(x*x+y*y),
|            t: Math.atan(x,y) 
|        };
|    }
 
The arguments, however, could be any object, and those act totally normally. If 
an object is given as argument to the function that is an Object, the function 
can access the "real" Object.prototype by using Object.getPrototypeOf(...).
 
|    window.newXHR = function newXHR(window) as serializable {
|        return new this.XMLHttpRequest();
|    }
|    
|    var xhr = window.newXHR(); 
 
However, it's also possible for the calling code not to give such information 
by passing only primitive values like string and numbers. I believe this is the 
most likely usage of this kind of function, at least from the web platform 
point of view.
 
 
 
The good thing about those functions, is that they can safely be sent over the 
wires to another thread, or to another web page, because they do not possibly 
rely on any state or context.
 
Formalizing those functions is also an important step towards enabling JS code 
to run safely deeper into the browser stack, by avoiding any possible use of 
objects that are not supposed to be interacted with at a given time (the 
calling code can control exactly what the called function has access to). 
 
A possible use case would be to defined arbitrary timing function for 
animations:
 
|    function x2(x) as serializable { return x*x; }
|    
|    // this is safe because SomeWebAnim knows he will call the function
 only with numbers, so the code cannot access the DOM while it's still 
being computed, or because the DOM actually lives in another thread than
 the animation code.
|    SomeWebAnim.timingFunction = x2; 
 
 
 
Is there some interest from anyone else in formalizing this for a future 
version of EcmaScript? Or any comment?
Francois
 
 
 
PS: for the purposes of safety, we may want to disallow "eval" and "Function" 
inside this environment to make sure the code can be compiled ahead of time in 
all cases, and not force the usage of an interpreter. this could also be let to 
the choice of the author but be exposed as a slightly different concept (ie: 
compilable + serializable vs serializable only).                                
        
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to