tc39 / proposal-function-implementation-hiding

JavaScript language proposal: function implementation hiding
https://ci.tc39.es/preview/tc39/ecma262/pull/1739
MIT License
98 stars 7 forks source link

More info regarding the difficulties involved in "cloning" functions #7

Closed spion closed 5 years ago

spion commented 6 years ago

I think it might be helpful if there was a slightly longer section that goes into the details of why cloning doesn't work, with a couple of examples demonstrating the problems.

spion commented 6 years ago

To clarify, while reading I was wondering if decorators for methods:

class Cls { 
  @Function.censoredMethod
  method() { console.log('Cant see me'); }
}

and wrappers for functions:

export let fn = Function.censored(function() { 

})

might be able to do the trick (and if not, why not)?

Thanks!

domenic commented 5 years ago

Great question; this relies on historical context which few people have.

It turns out cloning methods, and changing one small thing about them, is pretty fraught. In the run up to ES2015, we had a fn.toMethod() method which created a clone of fn with its [[HomeObject]] changed. From https://github.com/allenwb/ESideas/blob/master/dcltomethod.md#the-tomethod-solution :

However, cloning a function creates other complications. Is the clone a deep or shallow clone? In either case are all of the functions properties cloned or only some of them. If the function itself has function valued properties should toMethod be recursively applied to them with the clone as the argument? What happens if toMethod is applied to a built-in function, a bound function, or a callable Proxy object. Is it expected to also know how to clone those?

The answer used in the ES6 draft version of toMethod was to perform a shallow clone of the function excluding all own properties except for length. If any other properties needed to be included in the clone (either shallowly or deeply) it was up to caller to toMethod to take care of that copying after toMethod returned the clone to it. For this reason, the ES6 draft toMethod was best thought of as a primitive that was intended to be primarily used by mix-in libraries or other abstractions over objects. Such libraries would have needed to establish their own policies for dealing with the cloning issue and for dealing with various kinds of exotic function objects.

Ultimately, TC39 decided that toMethod was too complex and error-prone.

I will add a pointer to the readme explaining this.