operator overloading proposal

Igor Baklan io.baklan at gmail.com
Fri Jun 3 15:59:43 UTC 2016

I think it would be also nice to have some "low level API" that would allow
to provide some interceptor object, which will trap all operators
invocations in some block of code. (at least for cases when both/some
arguments of operation are not primitives). Then if this particular
interceptor can't handle given arguments, it should be able to delegate
execution of this operation to some "outer scope", assuming that at the
out-most level is present some default handler that always
executes/evaluates operations as it is specified now in JS.

So in code it may look like:


const localOperatorsInterceptor = Object.freeze({
  __proto__: null, // to prevent scope pollution when using this object
with ``with``-statement
  [Symbol.operatorsInterceptor]: Object.freeze({
    ["_+_"]: function(a, b, proceed) {
      console.log("operation(a+b):", a, b);
      return proceed(a,b);
    ["+_"]: function(a, proceed) {
      console.log("operation(+a):", a);
      return proceed(a);
    ["++_"]: function(a, proceed) {
      console.log("operation(++a):", a);
      // returned value will be assigned back to "target"
variable/expression and returned as result of (++_)
      return proceed(a);
    ["_++"]: function(a, proceed) {
      console.log("operation(a++):", a);
      // returned value will be assigned back to "target"
      // former value of "target" variable/expression will become result of
      return proceed(a);
    // etc

with(localOperatorsInterceptor) {
  var res = {x:"y"} + {a:"b"}; // this should log: operation(a+b):
({x:"y"}) ({a:"b"})
  console.log(res); // res should become NaN since interceptor delegates
execution to default operators handler
  var doInc = function(x) {
    return ++x;
  res = doInc({foo: "bar"}); // this should log: operation(++a): ({foo:
  console.log(res); // res should stay equal NaN since interceptor
delegates execution to default operators handler


It is proposed to use ``with`` statement to localise block of code to which
this interceptor is applied. Interceptor may be organised as frozen object
with only one property which name is some "well-known symbol", for an
instance ``Symbol.operatorsInterceptor``. Since it is not assumed that
interceptor has "normal" (string named) properties (and has ``__proto__ ==
null``) it should generally not pollute code block scope with some extra
names, but only affect how operators  are executed/evaluated inside that
block of code. Also if interceptor itself and handlers object too will be
both frozen, then it should not break engine optimisation capabilities.
Meaning that if some function expression is defined inside that
``with``-statement, than all operators inside that function can be resolved
at function expression evaluation time (since all "withed" objects contents
are final). Also it can be specified that even if interceptor handler
object is not frozen, then anyway some snapshot of it state can be taken
(and actually that handler snapshot may be used as effective operators
handler for ``with``-ed block of code).

So if this operators interceptor feature would be available then it would
be possible to implement any custom system of symbol to operation mapping
in different "third-party" operators overloading libraries, which can be
also good at first time - to let people do some experiments in this area.

Also for me it looks like a good thing to have possibility to control
whether some system of operators will be applied to some code or not. In
case of ``with``-based approach it is controlled "very" explicitly - unless
you specify some ``with(someOperatorsInterceptor)`` no operators
overloading will be applied to your code. An if you want override some
operators in some sub-block of code, you can always span that sub-block
with some other ``with(anotherOperatorsInterceptor)`` statement and
``anotherOperatorsInterceptor`` interceptor will take precedence over
previous/outer one in target sub-block of code.

Of course it would be more nice to use something like ``import`` instead of
``with``, like for example in Scala, ``import`` may serve like more
convenient form of ``with``:
  **Scala( ``{ import obj._; /*some code*/ }`` ) <==> Js( ``with (obj) {
/*some code*/ }`` )**
But since ``import`` is reserved for modules I am not sure whether it can
be adapted to serve for this purposes too.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160603/d0f85eb9/attachment-0001.html>

More information about the es-discuss mailing list