Maybe an example about how this proposal makes everything better for everyone would work ...
How it is now
<!DOCTYPE html>
<head>
<script>
const traps = {
construct(target, args) {
console.log('construct');
return Reflect.construct(target, args);
},
get(target, name) {
console.log('get', name);
if (
// guessing + pretending
// still error prone
name === 'new' &&
typeof target === 'function' &&
!('new' in target)
) {
return (...args) => traps.construct(target, args);
}
// fallback
return target[name];
}
};
// example code: foreign class + pyodide proxy
class Thing {}
const $Thing = new Proxy(Thing, traps);
console.log($Thing.new());
</script>
</head>
</html>
How it could be instead
<!DOCTYPE html>
<head>
<script src="https://unpkg.com/@ungap/new"></script>
<script>
// this is literally it:no magic guessing or pretending
const traps = {
construct(target, args) {
console.log('construct');
return Reflect.construct(target, args);
},
get(target, name) {
console.log('get', name);
return target[name];
}
};
// example code: foreign class + pyodide proxy
class Thing {}
const $Thing = new Proxy(Thing, traps);
console.log($Thing.new());
</script>
</head>
</html>
Moving parts, possible shenanigans, guessing ... all gone: it just works out of Proxy primitives which makes it easier to maintain and reason about.
In a real-world scenario though, the get
trap is way more complicated because of namespaces ... so let's see how a complete trap could look like (considering previous complexity on top without Function.prototype.new
):
<!DOCTYPE html>
<head>
<script src="https://unpkg.com/@ungap/new"></script>
<script>
function get(target, name) {
console.log('get', name);
const value = target[name];
switch (typeof value) {
case 'function': return new Proxy(value, cbTraps);
case 'object': if (value) return new Proxy(value, objTraps);
default: return value;
}
}
const cbTraps = {
construct(target, args, proxy) {
console.log('construct', proxy);
return Reflect.construct(target, args);
},
apply(target, self, args) {
console.log('apply', self /* is proxy */);
return target.apply(self, args);
},
get
};
const objTraps = { get };
// example code w/ namespace
class Thing {}
const { some } = new Proxy({ some: { Thing }}, objTraps);
console.log(some.Thing.new());
</script>
</head>
</html>
Nowhere in my examples I need to branch out regular logic or consider special meaning for any property or do anything different from what I'd do regularly with JS ... and this is the reason I am proposing Function.prototype.new
unless anyone can show me code that doesn't guess, never fails and is also easier or less complicated than just this one.
I don't think I have anything else to add but please, please, try to be a tiny bit open minded around this request: it would simplify and normalize by far interoperability with any present to future foreign PL dealing with JS: thank you!