introduction of statefull functions (inspired by Scala language) - advanced specification of "operator()" for arbitrary objects

Igor Baklan io.baklan at
Sat May 14 11:07:52 UTC 2016

Fist of all little bit more details. Here `@@apply` and `@@update` proposed
like some "fallback scenario" for "()" for non function objects (and not
Proxy objects) - generally for objects that do not support `"()"`

Currently js has `"()"` operation (lets call it `"_=_()"`) but has not
`"()="` operation (lets call it `"_()=_"`). Also operation "()" currently
applied only to a functions, but not applied to the arbitrary objects (even
when I create Proxy from arbitrary object and trying to implement "()" in
Proxy, it still not work since target object was not a function, as for me
it is more bug then feature:) ). So it supposed that if `obj` is not a
function, then operation `"()"` goes to fallback scenario and try to use
`obj[@@apply]` as an implementation of `"()"` operation for this `obj`
object. But if `obj` object is Proxy object, than it obtains this operation
as "direct" call of `apply` handler method (bypassing fallback to
`obj[@@apply]`) . So `obj[@@apply]` should be used for "()" operation in
some similar way as `vlaueOf` and `toString` are used by `"+"` operation -
when object itself natively support this operation (like Number, String,
etc does) the no fallback scenarios are used - `"+"` operation just do its
native implementation, but when object do not natively support `"+"` (case
of arbitrary object, not Number, not String, ...) then some additional
fallback actions happens (with calling `valueOf` / `toString`).
So here is the same idea - if `obj` is a function (or Proxy object) no
fallback actions should occur - operation "()" should be done "natively".
if object not a function neither a Proxy object, then fallback to
`obj[@@apply]` should occur (and signature of this `obj[@@apply]`-method
assumed to be the same as in proxy handler `apply` method
(`function(target, thisArg, argumentsList) {}`) - so it should obtain more
information then just a list of an arguments it also should obtain `target`
and `thisArg` where `target` should be bound to `obj` and `thisArg` should
be also properly passed, if it was `owner.obj(arg)` then `thisArg` should
be bound to `owner` (*NOT* to `obj`)).

For `"()="` operation (`obj(..args) = val`) currently no implementation
present (this construction unconditionally cause compile time error). But
if we assume that it really present/implemented, and name it as `update`
(like it was done in Scala), then `update` and `apply` in Proxy handler
should be in the same relationship as `get` and `set` , and once again, it
should be assumed that Prxoy object may "natively" implement update
operation, and "fallback scenario" related to `obj[@@update]` should NOT
happen for Proxy objects.

So more strict definition off behavior will look like this:
Considering `owner.obj(..args) = val` case:
1) If `owner.obj` is NOT a Proxy object (do not support `_()=_` operation
"natively") then this should be evaluated to
owner.obj[@@update](/*target:*/ owner.obj, /*thisArg:*/ owner, args)
2) If `owner.obj` is Proxy object (and that's why do support `_()=_`
operation "natively") then underling assignment should refer to Proxy
object handler `update` operation with same arguments as above, if proxy
handler do not support `update` implementation, than it can fallback to
`target` implantation of `_()=_` operation (and apply this rule recursively
but this time for `target`)

Considering this thoughts particular answer to your post will be:

> ... and we already have Proxy traps for method calls: `get` and `apply`

if `obj` is Proxy object, it assumed that it implements "`_=_()`" and
`"_()=_"` operations "natively" so it should not use `obj[@@apply]` and
`obj[@@update]` methods (and that is why `get` should not trigger), instead
"`_=_()`" and `"_()=_"` operations should be directly forwarded to proxy
handler (`apply` and `update` method accordingly) ; `obj[@@apply]` and
`obj[@@update]` methods should be used only for objects which are both not
js Function neither js Proxy object.

Also proposed `update` handler method is more like counterpart of `apply`,
like `set` proxy handler method is counterpart to `get` proxy handler

> But there's also an inherent compatibility issue. Whenever you add a new
trap, the deal is, all existing Proxy handlers were written without
consideration for the new operation. So old code, used in combination with
the new language feature, would tend to break.

In case if old code was used, then it should mean that no `update` method
present in proxy handler and so  that `obj(...args) = val` will fallback to
`target(...args) = val` (by actual result of execution); if `target` object
was also defined/constructed by old code, then construct `obj(...args) =
val` will lead to the same error as `target(...args) = val` does (since old
code will not implement it for `target` too), so nothing will change for
old code in this case; if old code of proxy will be applied for `target`
object from "new code" (that occasionally happen to implement `"_()=_"`
operation some how), then `obj(...args) = val` will succeed transparently
and has same result as `target(...args) = val`. And yes, "old code" proxy
handler will not intercept this situation, and that means that all handlers
that currently intercept all operations over object will became less
"universal". But this doesn't mean that "purely old" code will be broken in
any way by introduction of this feature.

[13:59:31.266] "mailto:es-discuss at Re: introduction
of statefull functions (inspired by Scala language)\n\t- advanced
specification of \"operator()\" for arbitrary objects&In-Reply-To=<
CAPh8+ZqbejjwsBVUsdMgrLU1_13PJcS9ZF4JUV0ZBuO6h1Okcw at>"

On 12 May 2016 at 22:02, Jason Orendorff <jason.orendorff at> wrote:

> The nice thing about @@symbol-named methods is that we *don't* have to
> extend the Proxy API for them. They're just method calls.
> This is why there's no hasInstance Proxy trap. `instanceof` basically
> boils down to a method call, and we already have Proxy traps for
> method calls: `get` and `apply`.
> It's a good thing, too, because adding a new Proxy trap is a last
> resort. Just from a conceptual standpoint, the less complicated
> objects are, the better; just because there are 14 *fundamental*
> operations on objects doesn't mean we're eager to add more. But
> there's also an inherent compatibility issue. Whenever you add a new
> trap, the deal is, all existing Proxy handlers were written without
> consideration for the new operation. So old code, used in combination
> with the new language feature, would tend to break.
> Cheers,
> -j
> On Thu, May 12, 2016 at 9:42 AM, Igor Baklan <io.baklan at> wrote:
> > It would be nice to "bring sense" to expressions like "obj(a1, ... , aN)
> =
> > val".  (like "obj(x)  = y")
> > In Scala langue it defined in pretty clear and simple way:
> >
> >    "obj(a1, ... , aN)" <==> "obj.apply(a1, ... , aN)"
> >    "obj(a1, ... , an) = val" <==> "obj.update(a1, ... , aN, val)"
> >
> > Of course this applied only to that cases when obj was not defined like
> > method (in case of regular methods "mth(args) = val" will cause compile
> time
> > error).
> > So in Scala even arrays and maps are accessed and updated using "()"
> > operator
> >
> >    js( arr[index] = val ) <==> scala( arr(index) = val )
> >
> > (see ,
> >
> > , etc)
> >
> > So the proposals are:
> >
> > (1) to introduce symbols like @@apply and @@update with very similar to
> > Scala meaning (for cases when 'obj.sttFunc' is not a function)
> >
> >   "obj.sttFunc(a1, ... , aN) = val" ==> "obj.sttFunc[Symbol.update]
> > (obj.sttFunc, obj, [a1, ... , aN], val)"
> >   "obj.sttFunc(a1, ... , aN)" ==> "obj.sttFunc[Symbol.apply]
> (obj.sttFunc,
> > obj, [a1, ... , aN])"
> >
> > (2) to extend Prxoy object specification to support update action along
> with
> > apply action:
> >
> > I would like to write something similar to
> >
> > var target = {
> >    jsApply: function(key){
> >       console.log("apply: ", key);
> >       return key;
> >    },
> >    jsUpdate: function(key, val){
> >       console.log("update: (", key, ") = ", val);
> >       return val;
> >    }
> > };
> > var sttFunc = new Proxy(target, {
> >    apply: function(target, thisArg, argumentsList) {
> >       target.jsApply.apply(thisArg, argumentsList);
> >    },
> >    update:  function(target, thisArg, argumentsList, assignValue) {
> >       target.jsApply.apply(thisArg,
> > Array.from(argumentsList).concat([assignValue]));
> >    }
> > });
> >
> > And then run it as following
> >
> >> sttFunc ("key") = "value";
> >
> > update: ( key ) =  value
> >
> >> sttFunc ("key");
> >
> > apply:  key
> > "key"
> >
> >
> > _______________________________________________
> > es-discuss mailing list
> > es-discuss at
> >
> >
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list