Re: Callable objects protocol
BTW, another reason I want that kind of "function literal" is because I deliberately want to not just expose a function, but expose one *with properties*, as part of a public API. - Isiah Meadows cont...@isiahmeadows.com www.isiahmeadows.com On Wed, Dec 5, 2018 at 12:27 PM Ranando King wrote: > > Andrea, if class-fields becomes the accepted standard for private then that > would work, but it's awfully redundant. A closure is the very definition of > "private" in ES. So what does it mean to have a `static #foo` lexically > declared? From inside the function, it would be no more private than `var > bar`. That would lead to confusion. See the problem? > > On Wed, Dec 5, 2018 at 10:02 AM Andrea Giammarchi > wrote: >> >> I don't think introducing `public` here has any value. We have `static #a = >> 1` eventually for private already, the default should follow the classes >> behavior, IMO >> >> On Wed, Dec 5, 2018 at 10:46 PM Ranando King wrote: >>> >>> That's the kind of thing I was shooting for with static lexical scope >>> variables. There's 2 problems with it given the way things are going >>> though. Take a look. >>> >>> ```js >>> function foo() { >>> static a=1, >>> b=2, >>> c=3; >>> } >>> ``` >>> By the way I'm thinking, this would create 3 static variables within foo >>> that are only initialized once and retain whatever value is set on them >>> across invocations. Basically, the object `foo` carries around a closure >>> containing those values. Problem is, this is private to foo. That conflicts >>> with class-fields and it's sigil-means-private model. >>> >>> Ignoring that, public static variables can also be done (but it'd be the >>> first ever introduction of `public` in ES. >>> ```js >>> function foo() { >>> static public a=1, >>> b=2, >>> c=3; >>> } >>> ``` >>> This would make `foo.a`, `foo.b`, & `foo.c` accessible as public properties >>> of `foo`. >>> >>> Think this needs to be a proposal? >>> >>> >>> On Wed, Dec 5, 2018 at 1:39 AM Isiah Meadows wrote: Personally, I'd prefer something else: a means of a function object literal that's still callable, but I can tack other properties to it easily. Something like this, maybe: ```js { (...args) { ... }, } ``` In this, the `this` value is set to the callee itself, not the given `this` value. Not married to the syntax, but I want the functionality. On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi wrote: > > > the apply hook needs objects anyway. > > I meant functions > > On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi > wrote: >> >> I've actually replied to the op, I didn't mean to answer you directly, >> but the only reason I wrote that is because I could, no other reasons. >> >> However, people unaware of the handleEvent pattern for event listeners >> often hope to be able to pass objects as listeners, ignoring the fact >> they can do that already (but they need a handleEvent method, own or >> inherited, in that object). >> >> There is at least another use case I can't remember now, but I do >> remember doing the Proxy dance before ending up realizing that the apply >> hook needs objects anyway. >> >> But yeah, I don't think it's a must have, specially because we can have >> something similar already, as shown in my example. >> >> >> On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: >>> >>> Maybe I asked it wrong. >>> >>> How is making an ordinary object callable at all useful for anything >>> that can't already be easily handled via objects and functions? >>> (looking for use cases here) >>> How does this make coding easier to do and understand? (for the AST >>> parser and for the human) >>> >>> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi >>> wrote: How about this: ```js // the poly if (!Symbol.callable) Symbol.callable = Symbol('callable'); // the setup class Callable extends Function { constructor(object) { super('return arguments.callee[Symbol.callable](...arguments)'); //sloppy mode FTW! Object.setPrototypeOf(this, object); } } // the example const obj = new Callable({ [Symbol.callable](value) { return value + this.value; }, value: 123 }); obj(7); // 130 ``` On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: > > const obj = { >
Re: Callable objects protocol
Andrea, if class-fields becomes the accepted standard for private then that would work, but it's awfully redundant. A closure is the very definition of "private" in ES. So what does it mean to have a `static #foo` lexically declared? From inside the function, it would be no more private than `var bar`. That would lead to confusion. See the problem? On Wed, Dec 5, 2018 at 10:02 AM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > I don't think introducing `public` here has any value. We have `static #a > = 1` eventually for private already, the default should follow the classes > behavior, IMO > > On Wed, Dec 5, 2018 at 10:46 PM Ranando King wrote: > >> That's the kind of thing I was shooting for with static lexical scope >> variables. There's 2 problems with it given the way things are going >> though. Take a look. >> >> ```js >> function foo() { >> static a=1, >> b=2, >> c=3; >> } >> ``` >> By the way I'm thinking, this would create 3 static variables within foo >> that are only initialized once and retain whatever value is set on them >> across invocations. Basically, the object `foo` carries around a closure >> containing those values. Problem is, this is private to foo. That conflicts >> with class-fields and it's sigil-means-private model. >> >> Ignoring that, public static variables can also be done (but it'd be the >> first ever introduction of `public` in ES. >> ```js >> function foo() { >> static public a=1, >> b=2, >> c=3; >> } >> ``` >> This would make `foo.a`, `foo.b`, & `foo.c` accessible as public >> properties of `foo`. >> >> Think this needs to be a proposal? >> >> >> On Wed, Dec 5, 2018 at 1:39 AM Isiah Meadows >> wrote: >> >>> Personally, I'd prefer something else: a means of a function object >>> literal that's still callable, but I can tack other properties to it >>> easily. Something like this, maybe: >>> >>> ```js >>> { >>> (...args) { ... }, >>> } >>> ``` >>> >>> In this, the `this` value is set to the callee itself, not the given >>> `this` value. >>> >>> Not married to the syntax, but I want the functionality. >>> On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> > the apply hook needs objects anyway. I meant functions On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > I've actually replied to the op, I didn't mean to answer you directly, > but the only reason I wrote that is because I could, no other reasons. > > However, people unaware of the handleEvent pattern for event listeners > often hope to be able to pass objects as listeners, ignoring the fact they > can do that already (but they need a handleEvent method, own or inherited, > in that object). > > There is at least another use case I can't remember now, but I do > remember doing the Proxy dance before ending up realizing that the apply > hook needs objects anyway. > > But yeah, I don't think it's a must have, specially because we can > have something similar already, as shown in my example. > > > On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > >> Maybe I asked it wrong. >> >> How is making an ordinary object callable at all useful for anything >> that can't already be easily handled via objects and functions? (looking >> for use cases here) >> How does this make coding easier to do and understand? (for the AST >> parser and for the human) >> >> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> How about this: >>> >>> ```js >>> >>> // the poly >>> if (!Symbol.callable) >>> Symbol.callable = Symbol('callable'); >>> >>> // the setup >>> class Callable extends Function { >>> constructor(object) { >>> super('return arguments.callee[Symbol.callable](...arguments)'); >>> //sloppy mode FTW! >>> Object.setPrototypeOf(this, object); >>> } >>> } >>> >>> >>> // the example >>> const obj = new Callable({ >>> [Symbol.callable](value) { >>> return value + this.value; >>> }, >>> value: 123 >>> }); >>> >>> obj(7); // 130 >>> >>> >>> ``` >>> >>> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >>> Something along the lines of Symbol.iterator protocol for defining callback objects i.e: Symbol.callable: const obj = { [Symbol.callable]: function (...args) { return this[Symbol.for('value')] }, [Symbol.for(''value')]: 'value', } assert(obj() === 'value') ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
I don't think introducing `public` here has any value. We have `static #a = 1` eventually for private already, the default should follow the classes behavior, IMO On Wed, Dec 5, 2018 at 10:46 PM Ranando King wrote: > That's the kind of thing I was shooting for with static lexical scope > variables. There's 2 problems with it given the way things are going > though. Take a look. > > ```js > function foo() { > static a=1, > b=2, > c=3; > } > ``` > By the way I'm thinking, this would create 3 static variables within foo > that are only initialized once and retain whatever value is set on them > across invocations. Basically, the object `foo` carries around a closure > containing those values. Problem is, this is private to foo. That conflicts > with class-fields and it's sigil-means-private model. > > Ignoring that, public static variables can also be done (but it'd be the > first ever introduction of `public` in ES. > ```js > function foo() { > static public a=1, > b=2, > c=3; > } > ``` > This would make `foo.a`, `foo.b`, & `foo.c` accessible as public > properties of `foo`. > > Think this needs to be a proposal? > > > On Wed, Dec 5, 2018 at 1:39 AM Isiah Meadows > wrote: > >> Personally, I'd prefer something else: a means of a function object >> literal that's still callable, but I can tack other properties to it >> easily. Something like this, maybe: >> >> ```js >> { >> (...args) { ... }, >> } >> ``` >> >> In this, the `this` value is set to the callee itself, not the given >> `this` value. >> >> Not married to the syntax, but I want the functionality. >> On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> > the apply hook needs objects anyway. >>> >>> I meant functions >>> >>> On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> I've actually replied to the op, I didn't mean to answer you directly, but the only reason I wrote that is because I could, no other reasons. However, people unaware of the handleEvent pattern for event listeners often hope to be able to pass objects as listeners, ignoring the fact they can do that already (but they need a handleEvent method, own or inherited, in that object). There is at least another use case I can't remember now, but I do remember doing the Proxy dance before ending up realizing that the apply hook needs objects anyway. But yeah, I don't think it's a must have, specially because we can have something similar already, as shown in my example. On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > Maybe I asked it wrong. > > How is making an ordinary object callable at all useful for anything > that can't already be easily handled via objects and functions? (looking > for use cases here) > How does this make coding easier to do and understand? (for the AST > parser and for the human) > > On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> How about this: >> >> ```js >> >> // the poly >> if (!Symbol.callable) >> Symbol.callable = Symbol('callable'); >> >> // the setup >> class Callable extends Function { >> constructor(object) { >> super('return arguments.callee[Symbol.callable](...arguments)'); >> //sloppy mode FTW! >> Object.setPrototypeOf(this, object); >> } >> } >> >> >> // the example >> const obj = new Callable({ >> [Symbol.callable](value) { >> return value + this.value; >> }, >> value: 123 >> }); >> >> obj(7); // 130 >> >> >> ``` >> >> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >> >>> Something along the lines of Symbol.iterator protocol for defining >>> callback objects i.e: Symbol.callable: >>> >>> const obj = { >>> [Symbol.callable]: function (...args) { return >>> this[Symbol.for('value')] }, >>> [Symbol.for(''value')]: 'value', >>> } >>> >>> assert(obj() === 'value') >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
That's the kind of thing I was shooting for with static lexical scope variables. There's 2 problems with it given the way things are going though. Take a look. ```js function foo() { static a=1, b=2, c=3; } ``` By the way I'm thinking, this would create 3 static variables within foo that are only initialized once and retain whatever value is set on them across invocations. Basically, the object `foo` carries around a closure containing those values. Problem is, this is private to foo. That conflicts with class-fields and it's sigil-means-private model. Ignoring that, public static variables can also be done (but it'd be the first ever introduction of `public` in ES. ```js function foo() { static public a=1, b=2, c=3; } ``` This would make `foo.a`, `foo.b`, & `foo.c` accessible as public properties of `foo`. Think this needs to be a proposal? On Wed, Dec 5, 2018 at 1:39 AM Isiah Meadows wrote: > Personally, I'd prefer something else: a means of a function object > literal that's still callable, but I can tack other properties to it > easily. Something like this, maybe: > > ```js > { > (...args) { ... }, > } > ``` > > In this, the `this` value is set to the callee itself, not the given > `this` value. > > Not married to the syntax, but I want the functionality. > On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> > the apply hook needs objects anyway. >> >> I meant functions >> >> On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> I've actually replied to the op, I didn't mean to answer you directly, >>> but the only reason I wrote that is because I could, no other reasons. >>> >>> However, people unaware of the handleEvent pattern for event listeners >>> often hope to be able to pass objects as listeners, ignoring the fact they >>> can do that already (but they need a handleEvent method, own or inherited, >>> in that object). >>> >>> There is at least another use case I can't remember now, but I do >>> remember doing the Proxy dance before ending up realizing that the apply >>> hook needs objects anyway. >>> >>> But yeah, I don't think it's a must have, specially because we can have >>> something similar already, as shown in my example. >>> >>> >>> On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: >>> Maybe I asked it wrong. How is making an ordinary object callable at all useful for anything that can't already be easily handled via objects and functions? (looking for use cases here) How does this make coding easier to do and understand? (for the AST parser and for the human) On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > How about this: > > ```js > > // the poly > if (!Symbol.callable) > Symbol.callable = Symbol('callable'); > > // the setup > class Callable extends Function { > constructor(object) { > super('return arguments.callee[Symbol.callable](...arguments)'); > //sloppy mode FTW! > Object.setPrototypeOf(this, object); > } > } > > > // the example > const obj = new Callable({ > [Symbol.callable](value) { > return value + this.value; > }, > value: 123 > }); > > obj(7); // 130 > > > ``` > > On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > >> Something along the lines of Symbol.iterator protocol for defining >> callback objects i.e: Symbol.callable: >> >> const obj = { >> [Symbol.callable]: function (...args) { return >> this[Symbol.for('value')] }, >> [Symbol.for(''value')]: 'value', >> } >> >> assert(obj() === 'value') >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Personally, I'd prefer something else: a means of a function object literal that's still callable, but I can tack other properties to it easily. Something like this, maybe: ```js { (...args) { ... }, } ``` In this, the `this` value is set to the callee itself, not the given `this` value. Not married to the syntax, but I want the functionality. On Wed, Dec 5, 2018 at 01:34 Andrea Giammarchi wrote: > > the apply hook needs objects anyway. > > I meant functions > > On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> I've actually replied to the op, I didn't mean to answer you directly, >> but the only reason I wrote that is because I could, no other reasons. >> >> However, people unaware of the handleEvent pattern for event listeners >> often hope to be able to pass objects as listeners, ignoring the fact they >> can do that already (but they need a handleEvent method, own or inherited, >> in that object). >> >> There is at least another use case I can't remember now, but I do >> remember doing the Proxy dance before ending up realizing that the apply >> hook needs objects anyway. >> >> But yeah, I don't think it's a must have, specially because we can have >> something similar already, as shown in my example. >> >> >> On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: >> >>> Maybe I asked it wrong. >>> >>> How is making an ordinary object callable at all useful for anything >>> that can't already be easily handled via objects and functions? (looking >>> for use cases here) >>> How does this make coding easier to do and understand? (for the AST >>> parser and for the human) >>> >>> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < >>> andrea.giammar...@gmail.com> wrote: >>> How about this: ```js // the poly if (!Symbol.callable) Symbol.callable = Symbol('callable'); // the setup class Callable extends Function { constructor(object) { super('return arguments.callee[Symbol.callable](...arguments)'); //sloppy mode FTW! Object.setPrototypeOf(this, object); } } // the example const obj = new Callable({ [Symbol.callable](value) { return value + this.value; }, value: 123 }); obj(7); // 130 ``` On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: > > const obj = { > [Symbol.callable]: function (...args) { return > this[Symbol.for('value')] }, > [Symbol.for(''value')]: 'value', > } > > assert(obj() === 'value') > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss >>> ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
> the apply hook needs objects anyway. I meant functions On Wed, Dec 5, 2018 at 1:33 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > I've actually replied to the op, I didn't mean to answer you directly, but > the only reason I wrote that is because I could, no other reasons. > > However, people unaware of the handleEvent pattern for event listeners > often hope to be able to pass objects as listeners, ignoring the fact they > can do that already (but they need a handleEvent method, own or inherited, > in that object). > > There is at least another use case I can't remember now, but I do remember > doing the Proxy dance before ending up realizing that the apply hook needs > objects anyway. > > But yeah, I don't think it's a must have, specially because we can have > something similar already, as shown in my example. > > > On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > >> Maybe I asked it wrong. >> >> How is making an ordinary object callable at all useful for anything that >> can't already be easily handled via objects and functions? (looking for use >> cases here) >> How does this make coding easier to do and understand? (for the AST >> parser and for the human) >> >> On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < >> andrea.giammar...@gmail.com> wrote: >> >>> How about this: >>> >>> ```js >>> >>> // the poly >>> if (!Symbol.callable) >>> Symbol.callable = Symbol('callable'); >>> >>> // the setup >>> class Callable extends Function { >>> constructor(object) { >>> super('return arguments.callee[Symbol.callable](...arguments)'); >>> //sloppy mode FTW! >>> Object.setPrototypeOf(this, object); >>> } >>> } >>> >>> >>> // the example >>> const obj = new Callable({ >>> [Symbol.callable](value) { >>> return value + this.value; >>> }, >>> value: 123 >>> }); >>> >>> obj(7); // 130 >>> >>> >>> ``` >>> >>> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >>> Something along the lines of Symbol.iterator protocol for defining callback objects i.e: Symbol.callable: const obj = { [Symbol.callable]: function (...args) { return this[Symbol.for('value')] }, [Symbol.for(''value')]: 'value', } assert(obj() === 'value') ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
I've actually replied to the op, I didn't mean to answer you directly, but the only reason I wrote that is because I could, no other reasons. However, people unaware of the handleEvent pattern for event listeners often hope to be able to pass objects as listeners, ignoring the fact they can do that already (but they need a handleEvent method, own or inherited, in that object). There is at least another use case I can't remember now, but I do remember doing the Proxy dance before ending up realizing that the apply hook needs objects anyway. But yeah, I don't think it's a must have, specially because we can have something similar already, as shown in my example. On Wed, Dec 5, 2018 at 1:25 PM Ranando King wrote: > Maybe I asked it wrong. > > How is making an ordinary object callable at all useful for anything that > can't already be easily handled via objects and functions? (looking for use > cases here) > How does this make coding easier to do and understand? (for the AST parser > and for the human) > > On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < > andrea.giammar...@gmail.com> wrote: > >> How about this: >> >> ```js >> >> // the poly >> if (!Symbol.callable) >> Symbol.callable = Symbol('callable'); >> >> // the setup >> class Callable extends Function { >> constructor(object) { >> super('return arguments.callee[Symbol.callable](...arguments)'); >> //sloppy mode FTW! >> Object.setPrototypeOf(this, object); >> } >> } >> >> >> // the example >> const obj = new Callable({ >> [Symbol.callable](value) { >> return value + this.value; >> }, >> value: 123 >> }); >> >> obj(7); // 130 >> >> >> ``` >> >> On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: >> >>> Something along the lines of Symbol.iterator protocol for defining >>> callback objects i.e: Symbol.callable: >>> >>> const obj = { >>> [Symbol.callable]: function (...args) { return >>> this[Symbol.for('value')] }, >>> [Symbol.for(''value')]: 'value', >>> } >>> >>> assert(obj() === 'value') >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Maybe I asked it wrong. How is making an ordinary object callable at all useful for anything that can't already be easily handled via objects and functions? (looking for use cases here) How does this make coding easier to do and understand? (for the AST parser and for the human) On Tue, Dec 4, 2018 at 11:54 PM Andrea Giammarchi < andrea.giammar...@gmail.com> wrote: > How about this: > > ```js > > // the poly > if (!Symbol.callable) > Symbol.callable = Symbol('callable'); > > // the setup > class Callable extends Function { > constructor(object) { > super('return arguments.callee[Symbol.callable](...arguments)'); > //sloppy mode FTW! > Object.setPrototypeOf(this, object); > } > } > > > // the example > const obj = new Callable({ > [Symbol.callable](value) { > return value + this.value; > }, > value: 123 > }); > > obj(7); // 130 > > > ``` > > On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > >> Something along the lines of Symbol.iterator protocol for defining >> callback objects i.e: Symbol.callable: >> >> const obj = { >> [Symbol.callable]: function (...args) { return >> this[Symbol.for('value')] }, >> [Symbol.for(''value')]: 'value', >> } >> >> assert(obj() === 'value') >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
How about this: ```js // the poly if (!Symbol.callable) Symbol.callable = Symbol('callable'); // the setup class Callable extends Function { constructor(object) { super('return arguments.callee[Symbol.callable](...arguments)'); //sloppy mode FTW! Object.setPrototypeOf(this, object); } } // the example const obj = new Callable({ [Symbol.callable](value) { return value + this.value; }, value: 123 }); obj(7); // 130 ``` On Wed, Dec 5, 2018 at 12:02 AM Sultan wrote: > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: > > const obj = { > [Symbol.callable]: function (...args) { return > this[Symbol.for('value')] }, > [Symbol.for(''value')]: 'value', > } > > assert(obj() === 'value') > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Ok. I get what you're after. So what's to be gained by being able to make an object directly callable over simply using functions? I remember that in C++ there was the concept of a "functor" where overloading `operator()` would allow you to treat instances as functions, and that had some limited utility to it (like creating delegate functions). But those use cases are already easily possible in ES by other means. On Tue, Dec 4, 2018 at 7:25 PM Sultan wrote: > Yes function objects are already callable objects. This is meant to allow > authors the ability to make callable non-function objects with this new > protocol. > > typeof nonFunctionCallableObject === 'object'. As much as Symbol.iterator > is used to determine if a non-native object is an iterator so too would > Symbol.callable with regards to non-function callables. > > One of the utilities of this can be visualized in the getter/setter type > callables: fn() gets the value, fn(a) sets the value, this is normally > supplied with methods to allow an outsider the ability to be reactive to > changes of the underlining value something akin to observables. > > One way to implement this is as T.J mentioned – using a closure: > > function closure () { > var value = 'value' > return function (a) { return arguments.length ? value = a : value } > } > > Another would be to treat functions as the objects they truly are: > > function object () { > function value (a) { return arguments.length ? this.value = a : this.value > } > value.value = null > } > > Or as this proposal would allow; > > An idiomatic class-based implementation with a shared callable protocol > that is extendable by other classes: > > class prototype { > [Symbol.callable](...args) { return args.length ? this.value = args[0] : > args[0] } > } > > const a = new prototype() > > assert(a(1) === 1, a() === 1) > > On Wed, Dec 5, 2018 at 1:15 AM Ranando King wrote: > >> Thinking again, this might be a request for static lexical scope >> variables such that: >> >> ```js >> function obj() { >> static value = { test: 42 }; >> return obj.value; >> } >> >> var a = obj(); >> assert(obj() === a); >> ``` >> >> On Tue, Dec 4, 2018 at 4:05 PM Ranando King wrote: >> >>> Ok maybe I'm thinking a little to literally, but isn't a function >>> already a callable object? >>> >>> ```js >>> function obj() { >>> return obj.value; >>> } >>> obj.value = "value"; >>> >>> assert(obj() === "value"); >>> ``` >>> >>> On Tue, Dec 4, 2018 at 1:16 PM Isiah Meadows >>> wrote: >>> >>>> Edit: the wrapper needs to be a function, so ignore that last email. >>>> It's wrong. >>>> >>>> - >>>> >>>> Isiah Meadows >>>> cont...@isiahmeadows.com >>>> www.isiahmeadows.com >>>> >>>> On Tue, Dec 4, 2018 at 2:14 PM Isiah Meadows >>>> wrote: >>>> > >>>> > BTW, there are proxies [1], and one of the proxy hooks is to intercept >>>> > calls [2]. >>>> > >>>> > [1]: >>>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy >>>> > [2]: >>>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply >>>> > >>>> > Your "callable object" proposal would be literally as simple as this >>>> > to implement: >>>> > >>>> > ```js >>>> > const callable = Symbol.for("callable") >>>> > const handler = { >>>> > apply(target, thisArg, argsList) { >>>> > return Reflect.apply(target[callable], thisArg, argsList) >>>> > }, >>>> > } >>>> > function makeCallable(obj) { return new Proxy(obj, handler) } >>>> > >>>> > // Your example, ported >>>> > const obj = makeCallable({ >>>> > [callable]: function (...args) { return this[Symbol.for('value')] >>>> }, >>>> > [Symbol.for(''value')]: 'value', >>>> > }) >>>> > >>>> > assert(obj() === 'value') >>>> > obj[callable] = () => 1 >>>> > assert(obj() === 1) >>>> > ``` >>>> > >>>> > - >>>> > >>>> > Isiah Meadows >>>> > cont...@isiahmeadows.com >>>> > www.isiahmeadows.com >>>> > On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: >>>> > > >>>> > > Something along the lines of Symbol.iterator protocol for defining >>>> callback objects i.e: Symbol.callable: >>>> > > >>>> > > const obj = { >>>> > > [Symbol.callable]: function (...args) { return >>>> this[Symbol.for('value')] }, >>>> > > [Symbol.for(''value')]: 'value', >>>> > > } >>>> > > >>>> > > assert(obj() === 'value') >>>> > > ___ >>>> > > es-discuss mailing list >>>> > > es-discuss@mozilla.org >>>> > > https://mail.mozilla.org/listinfo/es-discuss >>>> ___ >>>> es-discuss mailing list >>>> es-discuss@mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Yes function objects are already callable objects. This is meant to allow authors the ability to make callable non-function objects with this new protocol. typeof nonFunctionCallableObject === 'object'. As much as Symbol.iterator is used to determine if a non-native object is an iterator so too would Symbol.callable with regards to non-function callables. One of the utilities of this can be visualized in the getter/setter type callables: fn() gets the value, fn(a) sets the value, this is normally supplied with methods to allow an outsider the ability to be reactive to changes of the underlining value something akin to observables. One way to implement this is as T.J mentioned – using a closure: function closure () { var value = 'value' return function (a) { return arguments.length ? value = a : value } } Another would be to treat functions as the objects they truly are: function object () { function value (a) { return arguments.length ? this.value = a : this.value } value.value = null } Or as this proposal would allow; An idiomatic class-based implementation with a shared callable protocol that is extendable by other classes: class prototype { [Symbol.callable](...args) { return args.length ? this.value = args[0] : args[0] } } const a = new prototype() assert(a(1) === 1, a() === 1) On Wed, Dec 5, 2018 at 1:15 AM Ranando King wrote: > Thinking again, this might be a request for static lexical scope variables > such that: > > ```js > function obj() { > static value = { test: 42 }; > return obj.value; > } > > var a = obj(); > assert(obj() === a); > ``` > > On Tue, Dec 4, 2018 at 4:05 PM Ranando King wrote: > >> Ok maybe I'm thinking a little to literally, but isn't a function >> already a callable object? >> >> ```js >> function obj() { >> return obj.value; >> } >> obj.value = "value"; >> >> assert(obj() === "value"); >> ``` >> >> On Tue, Dec 4, 2018 at 1:16 PM Isiah Meadows >> wrote: >> >>> Edit: the wrapper needs to be a function, so ignore that last email. >>> It's wrong. >>> >>> - >>> >>> Isiah Meadows >>> cont...@isiahmeadows.com >>> www.isiahmeadows.com >>> >>> On Tue, Dec 4, 2018 at 2:14 PM Isiah Meadows >>> wrote: >>> > >>> > BTW, there are proxies [1], and one of the proxy hooks is to intercept >>> > calls [2]. >>> > >>> > [1]: >>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy >>> > [2]: >>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply >>> > >>> > Your "callable object" proposal would be literally as simple as this >>> > to implement: >>> > >>> > ```js >>> > const callable = Symbol.for("callable") >>> > const handler = { >>> > apply(target, thisArg, argsList) { >>> > return Reflect.apply(target[callable], thisArg, argsList) >>> > }, >>> > } >>> > function makeCallable(obj) { return new Proxy(obj, handler) } >>> > >>> > // Your example, ported >>> > const obj = makeCallable({ >>> > [callable]: function (...args) { return this[Symbol.for('value')] >>> }, >>> > [Symbol.for(''value')]: 'value', >>> > }) >>> > >>> > assert(obj() === 'value') >>> > obj[callable] = () => 1 >>> > assert(obj() === 1) >>> > ``` >>> > >>> > - >>> > >>> > Isiah Meadows >>> > cont...@isiahmeadows.com >>> > www.isiahmeadows.com >>> > On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: >>> > > >>> > > Something along the lines of Symbol.iterator protocol for defining >>> callback objects i.e: Symbol.callable: >>> > > >>> > > const obj = { >>> > > [Symbol.callable]: function (...args) { return >>> this[Symbol.for('value')] }, >>> > > [Symbol.for(''value')]: 'value', >>> > > } >>> > > >>> > > assert(obj() === 'value') >>> > > ___ >>> > > es-discuss mailing list >>> > > es-discuss@mozilla.org >>> > > https://mail.mozilla.org/listinfo/es-discuss >>> ___ >>> es-discuss mailing list >>> es-discuss@mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >> ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Thinking again, this might be a request for static lexical scope variables such that: ```js function obj() { static value = { test: 42 }; return obj.value; } var a = obj(); assert(obj() === a); ``` On Tue, Dec 4, 2018 at 4:05 PM Ranando King wrote: > Ok maybe I'm thinking a little to literally, but isn't a function > already a callable object? > > ```js > function obj() { > return obj.value; > } > obj.value = "value"; > > assert(obj() === "value"); > ``` > > On Tue, Dec 4, 2018 at 1:16 PM Isiah Meadows > wrote: > >> Edit: the wrapper needs to be a function, so ignore that last email. It's >> wrong. >> >> - >> >> Isiah Meadows >> cont...@isiahmeadows.com >> www.isiahmeadows.com >> >> On Tue, Dec 4, 2018 at 2:14 PM Isiah Meadows >> wrote: >> > >> > BTW, there are proxies [1], and one of the proxy hooks is to intercept >> > calls [2]. >> > >> > [1]: >> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy >> > [2]: >> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply >> > >> > Your "callable object" proposal would be literally as simple as this >> > to implement: >> > >> > ```js >> > const callable = Symbol.for("callable") >> > const handler = { >> > apply(target, thisArg, argsList) { >> > return Reflect.apply(target[callable], thisArg, argsList) >> > }, >> > } >> > function makeCallable(obj) { return new Proxy(obj, handler) } >> > >> > // Your example, ported >> > const obj = makeCallable({ >> > [callable]: function (...args) { return this[Symbol.for('value')] }, >> > [Symbol.for(''value')]: 'value', >> > }) >> > >> > assert(obj() === 'value') >> > obj[callable] = () => 1 >> > assert(obj() === 1) >> > ``` >> > >> > - >> > >> > Isiah Meadows >> > cont...@isiahmeadows.com >> > www.isiahmeadows.com >> > On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: >> > > >> > > Something along the lines of Symbol.iterator protocol for defining >> callback objects i.e: Symbol.callable: >> > > >> > > const obj = { >> > > [Symbol.callable]: function (...args) { return >> this[Symbol.for('value')] }, >> > > [Symbol.for(''value')]: 'value', >> > > } >> > > >> > > assert(obj() === 'value') >> > > ___ >> > > es-discuss mailing list >> > > es-discuss@mozilla.org >> > > https://mail.mozilla.org/listinfo/es-discuss >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Ok maybe I'm thinking a little to literally, but isn't a function already a callable object? ```js function obj() { return obj.value; } obj.value = "value"; assert(obj() === "value"); ``` On Tue, Dec 4, 2018 at 1:16 PM Isiah Meadows wrote: > Edit: the wrapper needs to be a function, so ignore that last email. It's > wrong. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > > On Tue, Dec 4, 2018 at 2:14 PM Isiah Meadows > wrote: > > > > BTW, there are proxies [1], and one of the proxy hooks is to intercept > > calls [2]. > > > > [1]: > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy > > [2]: > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply > > > > Your "callable object" proposal would be literally as simple as this > > to implement: > > > > ```js > > const callable = Symbol.for("callable") > > const handler = { > > apply(target, thisArg, argsList) { > > return Reflect.apply(target[callable], thisArg, argsList) > > }, > > } > > function makeCallable(obj) { return new Proxy(obj, handler) } > > > > // Your example, ported > > const obj = makeCallable({ > > [callable]: function (...args) { return this[Symbol.for('value')] }, > > [Symbol.for(''value')]: 'value', > > }) > > > > assert(obj() === 'value') > > obj[callable] = () => 1 > > assert(obj() === 1) > > ``` > > > > - > > > > Isiah Meadows > > cont...@isiahmeadows.com > > www.isiahmeadows.com > > On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: > > > > > > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: > > > > > > const obj = { > > > [Symbol.callable]: function (...args) { return > this[Symbol.for('value')] }, > > > [Symbol.for(''value')]: 'value', > > > } > > > > > > assert(obj() === 'value') > > > ___ > > > es-discuss mailing list > > > es-discuss@mozilla.org > > > https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
Edit: the wrapper needs to be a function, so ignore that last email. It's wrong. - Isiah Meadows cont...@isiahmeadows.com www.isiahmeadows.com On Tue, Dec 4, 2018 at 2:14 PM Isiah Meadows wrote: > > BTW, there are proxies [1], and one of the proxy hooks is to intercept > calls [2]. > > [1]: > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy > [2]: > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply > > Your "callable object" proposal would be literally as simple as this > to implement: > > ```js > const callable = Symbol.for("callable") > const handler = { > apply(target, thisArg, argsList) { > return Reflect.apply(target[callable], thisArg, argsList) > }, > } > function makeCallable(obj) { return new Proxy(obj, handler) } > > // Your example, ported > const obj = makeCallable({ > [callable]: function (...args) { return this[Symbol.for('value')] }, > [Symbol.for(''value')]: 'value', > }) > > assert(obj() === 'value') > obj[callable] = () => 1 > assert(obj() === 1) > ``` > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: > > > > Something along the lines of Symbol.iterator protocol for defining callback > > objects i.e: Symbol.callable: > > > > const obj = { > > [Symbol.callable]: function (...args) { return > > this[Symbol.for('value')] }, > > [Symbol.for(''value')]: 'value', > > } > > > > assert(obj() === 'value') > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
BTW, there are proxies [1], and one of the proxy hooks is to intercept calls [2]. [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply Your "callable object" proposal would be literally as simple as this to implement: ```js const callable = Symbol.for("callable") const handler = { apply(target, thisArg, argsList) { return Reflect.apply(target[callable], thisArg, argsList) }, } function makeCallable(obj) { return new Proxy(obj, handler) } // Your example, ported const obj = makeCallable({ [callable]: function (...args) { return this[Symbol.for('value')] }, [Symbol.for(''value')]: 'value', }) assert(obj() === 'value') obj[callable] = () => 1 assert(obj() === 1) ``` - Isiah Meadows cont...@isiahmeadows.com www.isiahmeadows.com On Tue, Dec 4, 2018 at 12:02 PM Sultan wrote: > > Something along the lines of Symbol.iterator protocol for defining callback > objects i.e: Symbol.callable: > > const obj = { > [Symbol.callable]: function (...args) { return this[Symbol.for('value')] > }, > [Symbol.for(''value')]: 'value', > } > > assert(obj() === 'value') > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
The type of the target is what affects typeof, indirectly by setting the [[Call]] value. If an `apply` or `construct` trap handler is given and the target isn't a function, they are ignored. See step 7 in https://www.ecma-international.org/ecma-262/9.0/index.html#sec-proxycreate On Tue, Dec 4, 2018 at 2:08 PM Isiah Meadows wrote: > BTW, `typeof new Proxy({}, {apply() { return 1 }})` returns > `"object"`, not `"function"`. Not sure this is any different. > > - > > Isiah Meadows > cont...@isiahmeadows.com > www.isiahmeadows.com > On Tue, Dec 4, 2018 at 2:02 PM Jordan Harband wrote: > > > > What would `typeof` return on a callable object? There's a lot of code > on the web that uses a typeof of "function" to determine if something is > safe to call. There's also a lot of code on the web that uses a typeof of > "function" to do type detection. How would you suggest a callable object > navigate these potentially conflicting constraints? > > > > On Tue, Dec 4, 2018 at 10:07 AM T.J. Crowder < > tj.crow...@farsightsoftware.com> wrote: > >> > >> On Tue, Dec 4, 2018 at 5:02 PM Sultan > >> wrote: > >> > > >> > Something along the lines of Symbol.iterator protocol for defining > >> > callback objects i.e: Symbol.callable: > >> > >> That's interesting. What's the primary motivation? Binding the data? > That's easily done with a closure ([fiddle[1]): > >> > >> ```js > >> const obj = (() => { > >> let value = 'value'; > >> return () => value; > >> })(); > >> > >> console.log(obj() === 'value'); // true > >> ``` > >> > >> It's a bit more verbose than one would like, but usually that's washed > out by the implementation (which is really trivial above). > >> > >> You can also do it with a Proxy on a function, but it doesn't really > buy you anything. > >> > >> Be interested to know more about why you want non-function callable > objects. > >> > >> -- T.J. Crowder > >> > >> [1]: http://jsfiddle.net/8qvpc7Lh/ > >> ___ > >> es-discuss mailing list > >> es-discuss@mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > > > > ___ > > es-discuss mailing list > > es-discuss@mozilla.org > > https://mail.mozilla.org/listinfo/es-discuss > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
BTW, `typeof new Proxy({}, {apply() { return 1 }})` returns `"object"`, not `"function"`. Not sure this is any different. - Isiah Meadows cont...@isiahmeadows.com www.isiahmeadows.com On Tue, Dec 4, 2018 at 2:02 PM Jordan Harband wrote: > > What would `typeof` return on a callable object? There's a lot of code on the > web that uses a typeof of "function" to determine if something is safe to > call. There's also a lot of code on the web that uses a typeof of "function" > to do type detection. How would you suggest a callable object navigate these > potentially conflicting constraints? > > On Tue, Dec 4, 2018 at 10:07 AM T.J. Crowder > wrote: >> >> On Tue, Dec 4, 2018 at 5:02 PM Sultan >> wrote: >> > >> > Something along the lines of Symbol.iterator protocol for defining >> > callback objects i.e: Symbol.callable: >> >> That's interesting. What's the primary motivation? Binding the data? That's >> easily done with a closure ([fiddle[1]): >> >> ```js >> const obj = (() => { >> let value = 'value'; >> return () => value; >> })(); >> >> console.log(obj() === 'value'); // true >> ``` >> >> It's a bit more verbose than one would like, but usually that's washed out >> by the implementation (which is really trivial above). >> >> You can also do it with a Proxy on a function, but it doesn't really buy you >> anything. >> >> Be interested to know more about why you want non-function callable objects. >> >> -- T.J. Crowder >> >> [1]: http://jsfiddle.net/8qvpc7Lh/ >> ___ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
What would `typeof` return on a callable object? There's a lot of code on the web that uses a typeof of "function" to determine if something is safe to call. There's also a lot of code on the web that uses a typeof of "function" to do type detection. How would you suggest a callable object navigate these potentially conflicting constraints? On Tue, Dec 4, 2018 at 10:07 AM T.J. Crowder < tj.crow...@farsightsoftware.com> wrote: > On Tue, Dec 4, 2018 at 5:02 PM Sultan > wrote: > > > > Something along the lines of Symbol.iterator protocol for defining > > callback objects i.e: Symbol.callable: > > That's interesting. What's the primary motivation? Binding the data? > That's easily done with a closure ([fiddle[1]): > > ```js > const obj = (() => { > let value = 'value'; > return () => value; > })(); > > console.log(obj() === 'value'); // true > ``` > > It's a bit more verbose than one would like, but usually that's washed out > by the implementation (which is really trivial above). > > You can also do it with a Proxy on a function, but it doesn't really buy > you anything. > > Be interested to know more about why you want non-function callable > objects. > > -- T.J. Crowder > > [1]: http://jsfiddle.net/8qvpc7Lh/ > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Callable objects protocol
On Tue, Dec 4, 2018 at 5:02 PM Sultan wrote: > > Something along the lines of Symbol.iterator protocol for defining > callback objects i.e: Symbol.callable: That's interesting. What's the primary motivation? Binding the data? That's easily done with a closure ([fiddle[1]): ```js const obj = (() => { let value = 'value'; return () => value; })(); console.log(obj() === 'value'); // true ``` It's a bit more verbose than one would like, but usually that's washed out by the implementation (which is really trivial above). You can also do it with a Proxy on a function, but it doesn't really buy you anything. Be interested to know more about why you want non-function callable objects. -- T.J. Crowder [1]: http://jsfiddle.net/8qvpc7Lh/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Callable objects protocol
Something along the lines of Symbol.iterator protocol for defining callback objects i.e: Symbol.callable: const obj = { [Symbol.callable]: function (...args) { return this[Symbol.for('value')] }, [Symbol.for(''value')]: 'value', } assert(obj() === 'value') ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Callable objects
Once there was a thread that discussed ability to configure any object as callable: http://mozilla.6506.n7.nabble.com/callable-objects-td99268.html Although it was then warmly welcomed, I don't see such possibility specified in latest draft I think it'll be really useful and we already deal with callable (and not functions) objects in some native interfaces. Is there any chance to bring @@call symbol or some other solution that would make that possible? -- View this message in context: http://mozilla.6506.n7.nabble.com/Callable-objects-tp290363.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 19/04/2012 01:00, Brendan Eich a écrit : David Bruant wrote: var p = Proxy(target, {}); p(); // throws exception because the proxy is reported as not having // a @call property In the get trap of the proxy, the @call private name is transformed into its public conterpart. When, by default, the trap forwards to the target, the public alter-ego is coerced into a string. Consequently, the actual @call property of the target isn't found. Hmm, I see. The idea was to avoid leaking private names via hostile proxies, but here we have a friendly proxy that wants to get the private-named target property. Yes. The interaction of proxies and private name has only been considered under the consideration that proxies can be hostile. And indeed, there are cases where there is no need to protect the private name from the proxy. One is publicly available private names (aka unique names). That was the root of the reasoning behind Alternative proposal to privateName.public [1]. I've summurized some approaches [2] that could be taken. With direct proxies, if the target already has the private-named property, and the handler ({} here) has no traps that might steal a non-substituted private name, why would we substitute the public name for the private @call? This doesn't scale. Private names could be added or removed from the target by some who have direct access to it (not intermediated with a proxy). David [1] https://mail.mozilla.org/pipermail/es-discuss/2011-December/018908.html [2] https://mail.mozilla.org/pipermail/es-discuss/2011-December/019005.html ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 19/04/2012 01:54, Brandon Benvie a écrit : (or you simply don't trap the access, which is the route for [[prototype]], [[instanceof]], etc which now makes even more sense to me in light of this) Not trapping seems like a valid option [1]. The rationale for the .public counterpart in the private name proposal is that the proxy should not have access to the private name. However, if it doesn't (directly or indirectly), it can't do anything useful. Under these conditions, the trap might as well not been called. David [1] https://mail.mozilla.org/pipermail/es-discuss/2011-December/019005.html ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
I still like the idea of distinguishing private from unique names, where private = invisible via reflection proxies and unique = visible via reflection proxies (cf. the thread David linked to). As for how direct proxies might help: yes, I've previously proposed several solutions: - One was to not allow proxies to trap private names, and always forward private name access unconditionally, as mentioned by Brandon. - The other was essentially Brendan's current proposal: if the trap is missing, forward the private name access to the target without converting it into a public object, except I also proposed factoring out private name access into separate getPrivate/setPrivate traps. See: https://mail.mozilla.org/pipermail/es-discuss/2011-December/018937.html https://mail.mozilla.org/pipermail/es-discuss/2011-December/018938.html Cheers, Tom 2012/4/19 David Bruant bruan...@gmail.com Le 19/04/2012 01:54, Brandon Benvie a écrit : (or you simply don't trap the access, which is the route for [[prototype]], [[instanceof]], etc which now makes even more sense to me in light of this) Not trapping seems like a valid option [1]. The rationale for the .public counterpart in the private name proposal is that the proxy should not have access to the private name. However, if it doesn't (directly or indirectly), it can't do anything useful. Under these conditions, the trap might as well not been called. David [1] https://mail.mozilla.org/**pipermail/es-discuss/2011-** December/019005.htmlhttps://mail.mozilla.org/pipermail/es-discuss/2011-December/019005.html __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 19/04/2012 16:55, Tom Van Cutsem a écrit : I still like the idea of distinguishing private from unique names, where private = invisible via reflection proxies and unique = visible via reflection proxies (cf. the thread David linked to). Additionally to this proposal, if the getOwnPropertyNames non-configurability invariant (must report all sealed properties) can be renegociated to not necessarily include unique names, then proxies can use unique names as private names (and not be forced to disclose them on Object.getOwnPropertyNames()). By the way, I'm realizing now that the getOwnPropertyNames trap does string coercion on elements of the array returned by the trap. How will this work with private names? Hopefully, these won't be coerced, but based on what? Will private names have a particular [[Native Brand]]? David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
David Bruant wrote: By the way, I'm realizing now that the getOwnPropertyNames trap does string coercion on elements of the array returned by the trap. How will this work with private names? Hopefully, these won't be coerced, but based on what? Will private names have a particular [[Native Brand]]? My understanding (not necessarily reflected in the private name objects proposal, alas) was that we would not break *any* existing reflection facility (for-in, Object.getOwnPropertyNames, etc.) by suddenly returning non-string property names. No reflection on private names. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
I'm sorry, but can somebody explain what the real use case for all this would be? And why proxies do not already cover it? Do we really need to make _every_ object into half a (mutable?) function proxy now? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 17/04/2012 22:44, Brendan Eich a écrit : Brendan Eich wrote: Irakli Gozalishvili wrote: It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Still hoping Mark will weigh in. Ok, I talked to Mark and Tom Van Cutsem, and they see no problem provided we prevent overriding built-in [[Call]] and [[Construct]] on function objects. Let there be private names @call and @construct (I'll spell them this way to avoid tedious imports of const bindings from @std or another built-in module). (...) This also simplifies direct proxies by allowing any proxy to have call and construct traps. Speaking of proxies and private names, how would the 2 private name interact with the proxies? It seems that it would be poorly because of the private-names-can-be-revealed-as-property-names-in-traps rule. Is it time to consider unique names? Since @call and @construct would be available to anyone, they are not much that private anyway. Change 11.4.3 The typeof Operator, the table row with Object (native or host and does implement [[Call]]) in column 1, to test not for [[Call]] and *not* for @call, rather to test [[NativeBrand]] === Function (see ES6 draft 15.2.4.2 Object.prototype.toString ( )). This last point is important: we do not want an object's typeof-type to change by giving it a @call property. This was a strong concern and the solution is satisfying as far as I'm concerned. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
The original post in this thread, from David Nolen, cited https://gist.github.com/2346460 In general there are more callable objects under the sun than function objects, but if the only way to make one is to write a proxy (now a direct proxy), the tax is too high: * Two object allocations not one. * A priori set-up when you might need mutation of an existing object to become callable. These may not motivate you, I'm not trying to sell anyone. We should discuss utility and trade-offs more, so thanks for posting. David mentioned Dart's considering a callable protocol too. I found this: http://groups.google.com/a/dartlang.org/group/misc/browse_frm/thread/6b4f18132adfaa78/c2cfd0daadba67f1?lnk=gstq=callable#c2cfd0daadba67f1 but I'm not sure if it is the latest. Perhaps you know more? /be Andreas Rossberg wrote: I'm sorry, but can somebody explain what the real use case for all this would be? And why proxies do not already cover it? Do we really need to make _every_ object into half a (mutable?) function proxy now? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 17/04/2012 22:44, Brendan Eich a écrit : Let there be private names @call and @construct (I'll spell them this way to avoid tedious imports of const bindings from @std or another built-in module). Let Clause 15.3.5 include new non-configurable, non-writable properties of function objects named by @call and @construct (built-in functions have only @call). The values are built-in and need a bit more thought than I can spare now, but see below: @call's value is close to the original value of Function.prototype.call, and @construct's value is straightforward enough I think. (...) Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). @call as own property only or is it inherited as well? David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
David Bruant wrote: Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). @call as own property only or is it inherited as well? I see no reason to require own. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 18/04/2012 17:14, Brendan Eich a écrit : David Bruant wrote: Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). @call as own property only or is it inherited as well? I see no reason to require own. After giving some more thoughts: function f(){ return 12; } var o = Object.create(f); o(); Currently this throws a TypeError (o isn't a function). If the @call property was inherited, the inherited @call would be called (and no error would be thrown). I don't know to what extent it matters, but it's worth noting there would be this difference. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Yes, I thought of that -- currently o() throws, so in the best case, there's no impediment to relaxing things to allow o() to call. In the worst case, code that caught or counted on the exception somehow might break. Mainly the own-only restriction seems less-good compared to how, e.g. proxy traps or accessors are found, via full prototype-based delegation. Are some of these proposed and novel base-level traps better off own-only, in spite of this general rule? /be David Bruant wrote: Le 18/04/2012 17:14, Brendan Eich a écrit : David Bruant wrote: Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). @call as own property only or is it inherited as well? I see no reason to require own. After giving some more thoughts: function f(){ return 12; } var o = Object.create(f); o(); Currently this throws a TypeError (o isn't a function). If the @call property was inherited, the inherited @call would be called (and no error would be thrown). I don't know to what extent it matters, but it's worth noting there would be this difference. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 18/04/2012 19:48, Brendan Eich a écrit : Mainly the own-only restriction seems less-good compared to how, e.g. proxy traps or accessors are found, via full prototype-based delegation. I agree with your point. However, I'd like to restate that interaction between proxies and private names as currently design is unusable: var callName = import @call; var target = { [callName]: function(){console.log('yo')} }; var p = Proxy(target, {}); p(); // throws exception because the proxy is reported as not having a @call property In the get trap of the proxy, the @call private name is transformed into its public conterpart. When, by default, the trap forwards to the target, the public alter-ego is coerced into a string. Consequently, the actual @call property of the target isn't found. Are some of these proposed and novel base-level traps better off own-only, in spite of this general rule? Did you mean traps or private properties? Assuming private properties. The precedent here is the different non-standard pseudo-properties. For __noSuchMethod__, it is inherited which is probably what is expected. I tested with: === var o = {}; o.__noSuchMethod__ = function(n){ console.log('__noSuchMethod__ call', n); } o.a(); var o2 = Object.create(o); o2.c() === __defineGetter__ and __defineSetter__ only made sense as if considered as own properties I think. __proto__ would make sense as an own property reflecting directly objects own internal [[Prototype]] property (which seems to be V8 behavior). Reality and security concerns make it a different story Besides specific cases of things that touch the specific aspects of singular object, I agree that inheriting is better. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
David Bruant wrote: Le 18/04/2012 19:48, Brendan Eich a écrit : Mainly the own-only restriction seems less-good compared to how, e.g. proxy traps or accessors are found, via full prototype-based delegation. I agree with your point. However, I'd like to restate that interaction between proxies and private names as currently design is unusable: var callName = import @call; var target = { [callName]: function(){console.log('yo')} }; Just as an aside, and to avoid confusion (import doesn't work that way), let's say it is: var target = { @call: function(){console.log('yo')} }; var p = Proxy(target, {}); p(); // throws exception because the proxy is reported as not having // a @call property In the get trap of the proxy, the @call private name is transformed into its public conterpart. When, by default, the trap forwards to the target, the public alter-ego is coerced into a string. Consequently, the actual @call property of the target isn't found. Hmm, I see. The idea was to avoid leaking private names via hostile proxies, but here we have a friendly proxy that wants to get the private-named target property. Tom, didn't our thinking on private names predate direct proxies? Or is that not relevant? In the old model, the handler would need traps (some fundamental ones at least) that special-case the public name substituted for @call. Perhaps we need something more automagic for direct proxies that still prevents private name leaks. With direct proxies, if the target already has the private-named property, and the handler ({} here) has no traps that might steal a non-substituted private name, why would we substitute the public name for the private @call? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Proxies seem to be able to support this well given a little bit of extra specification. A proxy attempts to forward the apply/construct action naively to its target. The result is it either succeeds or doesn't, and the same invariant checks would apply (private names have the same rules for configurability right?). The only difference is that a proxy won't know the result before actually attempting to follow through, which means that private non-configurable properties are a kind of booby trap if you *don't* always forward everything. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Errr that only applies to private properties that manifest in public results, as @construct and @call were described. In other cases the private name I would guess is simply not enforceable because there's no direct link between the private property and the outside world that has to be enforced. The shows a flaw of linking a private property with a predictable observable result. On Wed, Apr 18, 2012 at 7:26 PM, Brandon Benvie bran...@brandonbenvie.comwrote: Proxies seem to be able to support this well given a little bit of extra specification. A proxy attempts to forward the apply/construct action naively to its target. The result is it either succeeds or doesn't, and the same invariant checks would apply (private names have the same rules for configurability right?). The only difference is that a proxy won't know the result before actually attempting to follow through, which means that private non-configurable properties are a kind of booby trap if you *don't* always forward everything. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
The issue you may be missing (sorry if I'm mis-reading your post) is: hostile proxy passed into module that detects private-named properties on incoming objects. If the proxy has a handler that traps get, e.g., the private name will leak and the hostile party can now use it to decorate a trojan. So it seems to me the issue with direct proxies of whether the handler has a relevant trap for a given access matters. /be Brandon Benvie wrote: Proxies seem to be able to support this well given a little bit of extra specification. A proxy attempts to forward the apply/construct action naively to its target. The result is it either succeeds or doesn't, and the same invariant checks would apply (private names have the same rules for configurability right?). The only difference is that a proxy won't know the result before actually attempting to follow through, which means that private non-configurable properties are a kind of booby trap if you *don't* always forward everything. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
On Wed, Apr 18, 2012 at 4:31 PM, Brandon Benvie bran...@brandonbenvie.com wrote: Errr that only applies to private properties that manifest in public results, as @construct and @call were described. In other cases the private name I would guess is simply not enforceable because there's no direct link between the private property and the outside world that has to be enforced. The shows a flaw of linking a private property with a predictable observable result. The private name proposal has the ability to create ordinary unique names (same basic functionality, but enumerable and passed directly to proxies), right? Obviously all the names used in the standard library should be merely unique, not private, as you're not attempting to hide anything, just prevent accidental name clashes. ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
In that case I think it's worth noting that there is fundamentally different consequences between those two concepts then and requirements of one shouldn't be the same for the other. it's possible to have a private property that's non-configurable which has no bearing on proxies while that's obviously not true of anything public. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Good point, but http://wiki.ecmascript.org/doku.php?id=harmony:private_name_objects still has that visibility flag as an open issue. We need to settle this, sooner is better ;-). /be Tab Atkins Jr. wrote: On Wed, Apr 18, 2012 at 4:31 PM, Brandon Benvie bran...@brandonbenvie.com wrote: Errr that only applies to private properties that manifest in public results, as @construct and @call were described. In other cases the private name I would guess is simply not enforceable because there's no direct link between the private property and the outside world that has to be enforced. The shows a flaw of linking a private property with a predictable observable result. The private name proposal has the ability to create ordinary unique names (same basic functionality, but enumerable and passed directly to proxies), right? Obviously all the names used in the standard library should be merely unique, not private, as you're not attempting to hide anything, just prevent accidental name clashes. ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
This has been a useful thought experiment then. Private properties which are defined as directly linked to observable results seem to be a bad idea because that means a proxy is required to either always forward anything that can invoke that observable public/private relationship or the other option is unenforced invariants. If you keep the link between a private property and directly linked observable results opaque then you can allow proxies to completely ignore any invariant about them because there is no actual invariant to enforce. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Brendan Eich wrote: Irakli Gozalishvili wrote: It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Still hoping Mark will weigh in. Ok, I talked to Mark and Tom Van Cutsem, and they see no problem provided we prevent overriding built-in [[Call]] and [[Construct]] on function objects. Let there be private names @call and @construct (I'll spell them this way to avoid tedious imports of const bindings from @std or another built-in module). Let Clause 15.3.5 include new non-configurable, non-writable properties of function objects named by @call and @construct (built-in functions have only @call). The values are built-in and need a bit more thought than I can spare now, but see below: @call's value is close to the original value of Function.prototype.call, and @construct's value is straightforward enough I think. Change 11.2.2 The new Operator to use @construct not [[Construct]], passing the /argList// spread as actual positional parameters: (...argList). Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). Change 11.4.3 The typeof Operator, the table row with Object (native or host and does implement [[Call]]) in column 1, to test not for [[Call]] and *not* for @call, rather to test [[NativeBrand]] === Function (see ES6 draft 15.2.4.2 Object.prototype.toString ( )). This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. This also simplifies direct proxies by allowing any proxy to have call and construct traps. Comments welcome. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Brendan Eich wrote: This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. I did not include an Object.isCallable(v) API that returns true if (@call in v), but we could add that. Testing (@call in v) seems simple enough. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
+1 for simple enough. It's also shorter (12 vs 20) On Tue, Apr 17, 2012 at 2:02 PM, Brendan Eich bren...@mozilla.org wrote: Brendan Eich wrote: This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. I did not include an Object.isCallable(v) API that returns true if (@call in v), but we could add that. Testing (@call in v) seems simple enough. /be __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: callable objects ?
It seems rather non-intention-revealing. From: es-discuss-boun...@mozilla.org [es-discuss-boun...@mozilla.org] on behalf of Mark S. Miller [erig...@google.com] Sent: Tuesday, April 17, 2012 17:20 To: Brendan Eich Cc: Tom Van Cutsem; Mark Miller; es-discuss Subject: Re: callable objects ? +1 for simple enough. It's also shorter (12 vs 20) On Tue, Apr 17, 2012 at 2:02 PM, Brendan Eich bren...@mozilla.orgmailto:bren...@mozilla.org wrote: Brendan Eich wrote: This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. I did not include an Object.isCallable(v) API that returns true if (@call in v), but we could add that. Testing (@call in v) seems simple enough. /be ___ es-discuss mailing list es-discuss@mozilla.orgmailto:es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
On Tue, Apr 17, 2012 at 4:44 PM, Brendan Eich bren...@mozilla.org wrote: Brendan Eich wrote: Irakli Gozalishvili wrote: It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/**03/21/protocol-based-** polymorphism.html#posthttp://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Still hoping Mark will weigh in. Ok, I talked to Mark and Tom Van Cutsem, and they see no problem provided we prevent overriding built-in [[Call]] and [[Construct]] on function objects. Let there be private names @call and @construct (I'll spell them this way to avoid tedious imports of const bindings from @std or another built-in module). Let Clause 15.3.5 include new non-configurable, non-writable properties of function objects named by @call and @construct (built-in functions have only @call). The values are built-in and need a bit more thought than I can spare now, but see below: @call's value is close to the original value of Function.prototype.call, and @construct's value is straightforward enough I think. Change 11.2.2 The new Operator to use @construct not [[Construct]], passing the /argList// spread as actual positional parameters: (...argList). Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). Change 11.4.3 The typeof Operator, the table row with Object (native or host and does implement [[Call]]) in column 1, to test not for [[Call]] and *not* for @call, rather to test [[NativeBrand]] === Function (see ES6 draft 15.2.4.2 Object.prototype.toString ( )). This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. This also simplifies direct proxies by allowing any proxy to have call and construct traps. Comments welcome. What would happen if the object only defined one of these, but was used with the wrong one? Let's say I create an object Foo with @call, but not @construct, and then said new Foo()? Would it use @call and result in an error? What about vice versa? - Russ /be __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Already specified by ES6 as patched by my mail ;-). There's no fallback on @call from missing @construct. You have to say what you mean. If you define @call and someone uses 'new', without an inherited @construct you get a TypeError per 11.2.2 The new Operator. /be Russell Leggett wrote: What would happen if the object only defined one of these, but was used with the wrong one? Let's say I create an object Foo with @call, but not @construct, and then said new Foo()? Would it use @call and result in an error? What about vice versa? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Awesome. That gives you all the building blocks for trying out object exemplars via a library. I would add: [[HasInstance]] - @hasInstance On Apr 17, 2012, at 22:44 , Brendan Eich wrote: Brendan Eich wrote: Irakli Gozalishvili wrote: It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Still hoping Mark will weigh in. Ok, I talked to Mark and Tom Van Cutsem, and they see no problem provided we prevent overriding built-in [[Call]] and [[Construct]] on function objects. Let there be private names @call and @construct (I'll spell them this way to avoid tedious imports of const bindings from @std or another built-in module). Let Clause 15.3.5 include new non-configurable, non-writable properties of function objects named by @call and @construct (built-in functions have only @call). The values are built-in and need a bit more thought than I can spare now, but see below: @call's value is close to the original value of Function.prototype.call, and @construct's value is straightforward enough I think. Change 11.2.2 The new Operator to use @construct not [[Construct]], passing the /argList// spread as actual positional parameters: (...argList). Change 11.2.3 Function Calls to use @call not [[Call]], passing the /thisValue/ and /argList/ according to the Function.prototype.call convention: (thisValue, ...argList). Change 11.4.3 The typeof Operator, the table row with Object (native or host and does implement [[Call]]) in column 1, to test not for [[Call]] and *not* for @call, rather to test [[NativeBrand]] === Function (see ES6 draft 15.2.4.2 Object.prototype.toString ( )). This last point is important: we do not want an object's typeof-type to change by giving it a @call property. But we do want to enable call and construct protocols to be built by users, by giving objects @call and @construct properties. This also simplifies direct proxies by allowing any proxy to have call and construct traps. Comments welcome. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Axel Rauschmayer wrote: I would add: [[HasInstance]] - @hasInstance Yes, that one goes with @construct, and it seems safe to hook at base-level because only instanceof uses [[HasInstance]]. As Mark and Tom argued in the Proxy design docs, stratifying in a new proxy object is much safer when the trap is called all over, internally, and at points in ECMA-262 and real VMs where usercode is not expected to nest. Further-base level traps need to be considered carefully on a case-by-case basis. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Brendan Eich wrote: Let Clause 15.3.5 include new non-configurable, non-writable properties of function objects named by @call and @construct (built-in functions have only @call). Allen points out that for self-hosting Date and the like (this came up with the Intl work too, we think), leaving @construct configurable or at least writable is necessary. Tom and Mark rightly suggest that @call should not be something you can override on a function object. But is @construct safe to override? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
This is quite awesome. It seems like it might actually simplify a number of things in the process. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
On Tue, Apr 17, 2012 at 7:06 PM, Brendan Eich bren...@mozilla.org wrote: Axel Rauschmayer wrote: I would add: [[HasInstance]] - @hasInstance Yes, that one goes with @construct, and it seems safe to hook at base-level because only instanceof uses [[HasInstance]]. As Mark and Tom argued in the Proxy design docs, stratifying in a new proxy object is much safer when the trap is called all over, internally, and at points in ECMA-262 and real VMs where usercode is not expected to nest. Further-base level traps need to be considered carefully on a case-by-case basis. This is really nice to see! For a while now I've figured the separate namespace that name objects offer could be a really useful, simplifying force... Now to try and stretch this a bit further: I wonder if __proto__ shouldn't be stratified with a @prototypeOf name -- read-only, of course, except during instantiation. We ought to be able to write to the @prototypeOf name in a @construct function, right? Thus, if we could overwrite @construct on functions this could subsume | (or | -- I can never remember which direction that's supposed to point :P)... Of course if we were to go this far why not take it one more step and offer up a @constructor name that's invariably linked to the @construct function responsible for creating an instance? And finally, we may as well go all out and also stratify the prototype property with a @prototype name. This last one's not an immediate win (but seems like the right thing long term), but the others solve real problems in a way consistent with the @call and @construct approach above. I couldn't speak to whether it's safe to override a function's @construct but if it turns out to be, what do people think of this? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Also why would callable objects return `function` on `typeof(callable)`. As a matter of fact I think it should be `object` and something new like `Object.isCallable(object)` may be used to check for call-ability. This way old code either will reject non functions or will shim `Object.isCallable` to support new constructs. Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Wednesday, 2012-04-11 at 11:54 , Brendan Eich wrote: Michael Fogus wrote: I know some things about ClojureScript and would be happy to answer any direct questions. However, I think its notion (and Clojure proper) is that functions are data are functions is very powerful. It's a great idea (I first met John McCarthy in 1977 when I was 16). Too bad JS was not allowed to be Scheme in the browser. A lot of interesting patterns fall out of this as others have pointed out. I'm ready to jump in with both feet, except for JS's age and the possibility that too much code on the web counts on things like (typeof x == function) = x() works and x.apply is the expected built-in No problem, you say, we can leave typeof alone and add a callable predicate and evangelize that. Ok, provided the callable protocol uses an ES6 private name (think gensym), any public name could be in use and make a false positive when testing callability. So let's use a well-known private (unique, should say) name, e.g. module std { ... export const invokeName = Name.create(invoke); export function callable(v) { if (typeof v == function) return true; if (typeof v == object v != null) return invokeName in v; // could be pickier but let's start here return false; } } // make an object obj be callable: obj[invokeName] = function (...args) { /* ... */ }; Looks ok, ignoring details such as how the client code gets the standard unique name binding (import invokeName from @std or some such). One can't assume apply or call or other Function.prototype heritage is in x just because callable(x) returns true. Callability is wider and weaker than typeof-result function. IIRC, security conscious folks do not want an attacker to be able to make any old object callable. Cc'ing Mark for his thoughts. /be ___ es-discuss mailing list es-discuss@mozilla.org (mailto:es-discuss@mozilla.org) https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Irakli Gozalishvili wrote: It would be amazing to have clojure like protocols in JS even without `IFn`. I think it's very good feet and very useful in JS where each library has it's own flavored API. I wrote more about it here: http://jeditoolkit.com/2012/03/21/protocol-based-polymorphism.html#post Still hoping Mark will weigh in. Also why would callable objects return `function` on `typeof(callable)`. I didn't say that was a good idea, I only noted that we're breaking an invariant for native objects. Not unthinkable! As a matter of fact I think it should be `object` and something new like `Object.isCallable(object)` See callable(x) below. Putting it on Object and using isCallable Java-style naming seems safer but makes me sad -- so verbose! /be may be used to check for call-ability. This way old code either will reject non functions or will shim `Object.isCallable` to support new constructs. Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Wednesday, 2012-04-11 at 11:54 , Brendan Eich wrote: Michael Fogus wrote: I know some things about ClojureScript and would be happy to answer any direct questions. However, I think its notion (and Clojure proper) is that functions are data are functions is very powerful. It's a great idea (I first met John McCarthy in 1977 when I was 16). Too bad JS was not allowed to be Scheme in the browser. A lot of interesting patterns fall out of this as others have pointed out. I'm ready to jump in with both feet, except for JS's age and the possibility that too much code on the web counts on things like (typeof x == function) = x() works and x.apply is the expected built-in No problem, you say, we can leave typeof alone and add a callable predicate and evangelize that. Ok, provided the callable protocol uses an ES6 private name (think gensym), any public name could be in use and make a false positive when testing callability. So let's use a well-known private (unique, should say) name, e.g. module std { ... export const invokeName = Name.create(invoke); export function callable(v) { if (typeof v == function) return true; if (typeof v == object v != null) return invokeName in v; // could be pickier but let's start here return false; } } // make an object obj be callable: obj[invokeName] = function (...args) { /* ... */ }; Looks ok, ignoring details such as how the client code gets the standard unique name binding (import invokeName from @std or some such). One can't assume apply or call or other Function.prototype heritage is in x just because callable(x) returns true. Callability is wider and weaker than typeof-result function. IIRC, security conscious folks do not want an attacker to be able to make any old object callable. Cc'ing Mark for his thoughts. /be ___ es-discuss mailing list es-discuss@mozilla.org mailto:es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
callable objects ?
I know some things about ClojureScript and would be happy to answer any direct questions. However, I think its notion (and Clojure proper) is that functions are data are functions is very powerful. A lot of interesting patterns fall out of this as others have pointed out. Brendan Eich wrote: This gist about ClojureScript https://gist.github.com/2346460 reminded me of this thread. I need to spend more time learning ClojureScript; maybe someone who knows it has a thought. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
This extremely useful feature is under discussion for Dart as well. David On Wed, Apr 11, 2012 at 1:15 PM, Michael Fogus mefo...@gmail.com wrote: I know some things about ClojureScript and would be happy to answer any direct questions. However, I think its notion (and Clojure proper) is that functions are data are functions is very powerful. A lot of interesting patterns fall out of this as others have pointed out. Brendan Eich wrote: This gist about ClojureScript https://gist.github.com/2346460 reminded me of this thread. I need to spend more time learning ClojureScript; maybe someone who knows it has a thought. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Michael Fogus wrote: I know some things about ClojureScript and would be happy to answer any direct questions. However, I think its notion (and Clojure proper) is that functions are data are functions is very powerful. It's a great idea (I first met John McCarthy in 1977 when I was 16). Too bad JS was not allowed to be Scheme in the browser. A lot of interesting patterns fall out of this as others have pointed out. I'm ready to jump in with both feet, except for JS's age and the possibility that too much code on the web counts on things like (typeof x == function) = x() works and x.apply is the expected built-in No problem, you say, we can leave typeof alone and add a callable predicate and evangelize that. Ok, provided the callable protocol uses an ES6 private name (think gensym), any public name could be in use and make a false positive when testing callability. So let's use a well-known private (unique, should say) name, e.g. module std { ... export const invokeName = Name.create(invoke); export function callable(v) { if (typeof v == function) return true; if (typeof v == object v != null) return invokeName in v; // could be pickier but let's start here return false; } } // make an object obj be callable: obj[invokeName] = function (...args) { /* ... */ }; Looks ok, ignoring details such as how the client code gets the standard unique name binding (import invokeName from @std or some such). One can't assume apply or call or other Function.prototype heritage is in x just because callable(x) returns true. Callability is wider and weaker than typeof-result function. IIRC, security conscious folks do not want an attacker to be able to make any old object callable. Cc'ing Mark for his thoughts. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
JS was not allowed to be Scheme in the browser. There will be 42 Scheme-JS transpilers by the end of 2012. ;-) No problem, you say, we can leave typeof alone and add a callable predicate and evangelize that. Ok, provided the callable protocol uses an ES6 private name (think gensym), any public name could be in use and make a false positive when testing callability. Most of what you describe is a consequence of backwards compatibility and maximum dynamicity. ClojureScript gets a pass on these problems (for the most part) because of its focus for use and compilation model. Agreed adding these capabilities into JS is a sticky situation and not something that I envy. I'm glad smarter people than me are working on it. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
This gist about ClojureScript https://gist.github.com/2346460 reminded me of this thread. I need to spend more time learning ClojureScript; maybe someone who knows it has a thought. /be Irakli Gozalishvili wrote: I have prototyped desugared version of callable objects here: https://gist.github.com/2312621 I could not use short object syntax and unnamed method as proposed in original post, so I used regular object syntax and `new` as method name for unnamed `method`. I tried to illustrates that callable objects may be more elegant alternative to classes specially in combination with `|` (which I expressed as `extend` function). Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Wednesday, 2012-04-04 at 24:56 , David Bruant wrote: Le 04/04/2012 02:41, Irakli Gozalishvili a écrit : On Tuesday, 2012-04-03 at 14:07 , David Bruant wrote: Le 03/04/2012 22:00, Irakli Gozalishvili a écrit : Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } Interesting new function syntax. The prototype and function body could even be declared together. What about 'length'? Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); +1 Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value So far so good. key(map) // = value This cannot work for backward-compat reasons. In ES1-5, key = {} creates a regular (non-callable) object. Well I did not suggested it should be backwards compatible, also nor classes nor shorter object syntax is backwards compatible. They are to the extent that they throw an error for being invalid syntax in previous version. This is the case for your proposal and that's a good thing since that's the back door to introducing new features. However, proposals should be backward compatible in semantics. In your case: var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value since key is callable, you have (typeof key === 'function') while ES5 requires (typeof key === 'object') for objects that are constructed with '{}'. There is code out there that relies on typeof for argument shifting: 'if the first argument is a function, use that as callback, otherwise, use the second argument (first argument being an option non-callable object)'. There is this pattern all over the place in the mongodb node client as in https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L85 In other cases, to pass a handler, some API check if the argument if an object and in that case use the 'handle' property or use the function is what has been passed is callable. So, preserving typeof invariants regarding 'object'/'function' is crucial to backward compatibility. Likewise for arrays. In ES1-5, (typeof [] === 'object') and the suggested semantics of your proposal would break that. As far as I'm concerned, just the object-literal version of function is a brilliant idea, no need for the additional semantics. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
I have prototyped desugared version of callable objects here: https://gist.github.com/2312621 I could not use short object syntax and unnamed method as proposed in original post, so I used regular object syntax and `new` as method name for unnamed `method`. I tried to illustrates that callable objects may be more elegant alternative to classes specially in combination with `|` (which I expressed as `extend` function). Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Wednesday, 2012-04-04 at 24:56 , David Bruant wrote: Le 04/04/2012 02:41, Irakli Gozalishvili a écrit : On Tuesday, 2012-04-03 at 14:07 , David Bruant wrote: Le 03/04/2012 22:00, Irakli Gozalishvili a écrit : Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } Interesting new function syntax. The prototype and function body could even be declared together. What about 'length'? Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); +1 Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value So far so good. key(map) // = value This cannot work for backward-compat reasons. In ES1-5, key = {} creates a regular (non-callable) object. Well I did not suggested it should be backwards compatible, also nor classes nor shorter object syntax is backwards compatible. They are to the extent that they throw an error for being invalid syntax in previous version. This is the case for your proposal and that's a good thing since that's the back door to introducing new features. However, proposals should be backward compatible in semantics. In your case: var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value since key is callable, you have (typeof key === 'function') while ES5 requires (typeof key === 'object') for objects that are constructed with '{}'. There is code out there that relies on typeof for argument shifting: 'if the first argument is a function, use that as callback, otherwise, use the second argument (first argument being an option non-callable object)'. There is this pattern all over the place in the mongodb node client as in https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L85 In other cases, to pass a handler, some API check if the argument if an object and in that case use the 'handle' property or use the function is what has been passed is callable. So, preserving typeof invariants regarding 'object'/'function' is crucial to backward compatibility. Likewise for arrays. In ES1-5, (typeof [] === 'object') and the suggested semantics of your proposal would break that. As far as I'm concerned, just the object-literal version of function is a brilliant idea, no need for the additional semantics. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 04/04/2012 02:41, Irakli Gozalishvili a écrit : On Tuesday, 2012-04-03 at 14:07 , David Bruant wrote: Le 03/04/2012 22:00, Irakli Gozalishvili a écrit : Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } Interesting new function syntax. The prototype and function body could even be declared together. What about 'length'? Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); +1 Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value So far so good. key(map) // = value This cannot work for backward-compat reasons. In ES1-5, key = {} creates a regular (non-callable) object. Well I did not suggested it should be backwards compatible, also nor classes nor shorter object syntax is backwards compatible. They are to the extent that they throw an error for being invalid syntax in previous version. This is the case for your proposal and that's a good thing since that's the back door to introducing new features. However, proposals should be backward compatible in semantics. In your case: var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value since key is callable, you have (typeof key === 'function') while ES5 requires (typeof key === 'object') for objects that are constructed with '{}'. There is code out there that relies on typeof for argument shifting: 'if the first argument is a function, use that as callback, otherwise, use the second argument (first argument being an option non-callable object)'. There is this pattern all over the place in the mongodb node client as in https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L85 In other cases, to pass a handler, some API check if the argument if an object and in that case use the 'handle' property or use the function is what has been passed is callable. So, preserving typeof invariants regarding 'object'/'function' is crucial to backward compatibility. Likewise for arrays. In ES1-5, (typeof [] === 'object') and the suggested semantics of your proposal would break that. As far as I'm concerned, just the object-literal version of function is a brilliant idea, no need for the additional semantics. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
I agree that this is really elegant. I have almost the exact same construct in a language I'm designing. I don't know if it has a place in JS, but you have my approval. :) - Russ On Tue, Apr 3, 2012 at 4:00 PM, Irakli Gozalishvili rfo...@gmail.comwrote: Hi, Please excuse me if this will sound too crazy, but this idea have being growing in my head for so long that I can't stop myself from proposing it here. I have experimented many different ways of doing inheritance in JS: 1. Starting with a simple sugar that reduces machinery involved, similar to backbone.js https://github.com/Gozala/extendables 2. Finishing with class free prototypal inheritance https://github.com/Gozala/selfish I have to say that experience with selfish turned out very interesting, it made things so much simpler no special forms, no twisted relations between constructors and objects, just a plain objects. Most of these things are not obvious until you start using them, but the fact that exemplars (classes) are no different from regular objects in the system makes things much simpler. That being said I have also came to realize that in most of the cases functions as exemplars would be a better feet than objects. As a matter of fact if objects could be made callable I think it could could have replaced most of the things that classes are targeting in more elegant way. Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } var a = new Point(0, 0) var b = new Point(1, 7) // Examples from class proposal // extend is like create with a diff that second arg is an object. var SkinnedMesh = Object.extend(THREE.Mesh, { (geometry, materials) { // call the superclass constructor THREE.Mesh.call(this, geometry, materials); // initialize instance properties this.identityMatrix = new THREE.Matrix4(); this.bones = []; this.boneMatrices = []; // ... } update (camera) { THREE.Mesh.update.call(this); } }); Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value And maybe built-ins could have it for doing `[]` work: // Maybe even non-magical replacement for `[]` [ 'a', 'b', 'c' ](1) // = 'b' ({ a: 1, b: 2 })('a') // = 1 ('b')({ a: 1, b: 2 }) // = 2 Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Le 03/04/2012 22:00, Irakli Gozalishvili a écrit : Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } Interesting new function syntax. The prototype and function body could even be declared together. What about 'length'? Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); +1 Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value So far so good. key(map) // = value This cannot work for backward-compat reasons. In ES1-5, key = {} creates a regular (non-callable) object. And maybe built-ins could have it for doing `[]` work: // Maybe even non-magical replacement for `[]` [ 'a', 'b', 'c' ](1) // = 'b' Again, this is a valid ES1-5 expression and throws an error. Arrays and function have diverging opinions on the 'length' property. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
On Tuesday, 2012-04-03 at 14:07 , David Bruant wrote: Le 03/04/2012 22:00, Irakli Gozalishvili a écrit : Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } Interesting new function syntax. The prototype and function body could even be declared together. What about 'length'? Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); +1 Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value So far so good. key(map) // = value This cannot work for backward-compat reasons. In ES1-5, key = {} creates a regular (non-callable) object. Well I did not suggested it should be backwards compatible, also nor classes nor shorter object syntax is backwards compatible. And maybe built-ins could have it for doing `[]` work: // Maybe even non-magical replacement for `[]` [ 'a', 'b', 'c' ](1) // = 'b' Again, this is a valid ES1-5 expression and throws an error. Arrays and function have diverging opinions on the 'length' property. David Also de-sugared version may be provided (and even prototyped today using __proto__): var Point = Function.create(Object.prototype, function(x, y) { this.getX = function() { return x }; this.getY = function() { return y }; }, { toString: function() { return '' + this.getX() + ',' + this.getY() + '' } }); ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
On Tuesday, 2012-04-03 at 13:47 , Axel Rauschmayer wrote: I think you should make the distinction between [[Call]] and [[Construct]]. You can do it via (this insntanceof ..) already and dispatch to call / construct if you want. But both would be great to have for objects. It’s probably best to create importable names. Importable names won't allow shorter than function form though, so I think just () {} is better. Then making the `new` operator available to object exemplars becomes indeed simple. For example: // Root object exemplar import Construct from somewhere; let ObjectExemplar = { [Construct](...args) { let inst = Object.create(this); let result = inst.init(...args); return (result === undefined ? inst : result); } } On Apr 3, 2012, at 22:00 , Irakli Gozalishvili wrote: Hi, Please excuse me if this will sound too crazy, but this idea have being growing in my head for so long that I can't stop myself from proposing it here. I have experimented many different ways of doing inheritance in JS: 1. Starting with a simple sugar that reduces machinery involved, similar to backbone.js https://github.com/Gozala/extendables 2. Finishing with class free prototypal inheritance https://github.com/Gozala/selfish I have to say that experience with selfish turned out very interesting, it made things so much simpler no special forms, no twisted relations between constructors and objects, just a plain objects. Most of these things are not obvious until you start using them, but the fact that exemplars (classes) are no different from regular objects in the system makes things much simpler. That being said I have also came to realize that in most of the cases functions as exemplars would be a better feet than objects. As a matter of fact if objects could be made callable I think it could could have replaced most of the things that classes are targeting in more elegant way. Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } var a = new Point(0, 0) var b = new Point(1, 7) // Examples from class proposal // extend is like create with a diff that second arg is an object. var SkinnedMesh = Object.extend(THREE.Mesh, { (geometry, materials) { // call the superclass constructor THREE.Mesh.call(this, geometry, materials); // initialize instance properties this.identityMatrix = new THREE.Matrix4(); this.bones = []; this.boneMatrices = []; // ... } update (camera) { THREE.Mesh.update.call(this); } }); Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value And maybe built-ins could have it for doing `[]` work: // Maybe even non-magical replacement for `[]` [ 'a', 'b', 'c' ](1) // = 'b' ({ a: 1, b: 2 })('a') // = 1 ('b')({ a: 1, b: 2 }) // = 2 Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ ___ es-discuss mailing list es-discuss@mozilla.org (mailto:es-discuss@mozilla.org) https://mail.mozilla.org/listinfo/es-discuss -- Dr. Axel Rauschmayer a...@rauschma.de (mailto:a...@rauschma.de) home: rauschma.de (http://rauschma.de)twitter: twitter.com/rauschma (http://twitter.com/rauschma) blog: 2ality.com (http://2ality.com) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: callable objects ?
Also I just realized that I have not mentioned it but I meant that new Point(0, 0) would do following: var point = Object.create(Point); var value = Function.apply.call(point, arguments); return typeof(value) === 'undefined' ? point : value; Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Tuesday, 2012-04-03 at 17:44 , Irakli Gozalishvili wrote: On Tuesday, 2012-04-03 at 13:47 , Axel Rauschmayer wrote: I think you should make the distinction between [[Call]] and [[Construct]]. You can do it via (this insntanceof ..) already and dispatch to call / construct if you want. But both would be great to have for objects. It’s probably best to create importable names. Importable names won't allow shorter than function form though, so I think just () {} is better. Then making the `new` operator available to object exemplars becomes indeed simple. For example: // Root object exemplar import Construct from somewhere; let ObjectExemplar = { [Construct](...args) { let inst = Object.create(this); let result = inst.init(...args); return (result === undefined ? inst : result); } } On Apr 3, 2012, at 22:00 , Irakli Gozalishvili wrote: Hi, Please excuse me if this will sound too crazy, but this idea have being growing in my head for so long that I can't stop myself from proposing it here. I have experimented many different ways of doing inheritance in JS: 1. Starting with a simple sugar that reduces machinery involved, similar to backbone.js https://github.com/Gozala/extendables 2. Finishing with class free prototypal inheritance https://github.com/Gozala/selfish I have to say that experience with selfish turned out very interesting, it made things so much simpler no special forms, no twisted relations between constructors and objects, just a plain objects. Most of these things are not obvious until you start using them, but the fact that exemplars (classes) are no different from regular objects in the system makes things much simpler. That being said I have also came to realize that in most of the cases functions as exemplars would be a better feet than objects. As a matter of fact if objects could be made callable I think it could could have replaced most of the things that classes are targeting in more elegant way. Here is more or less what I have in mind: https://gist.github.com/2295048 // class var Point = { (x, y) { this.getX = { () { return x; } } this.getY = { () { return x; } } } toString() { return '' + this.getX() + ',' + this.getY() + ''; } } var a = new Point(0, 0) var b = new Point(1, 7) // Examples from class proposal // extend is like create with a diff that second arg is an object. var SkinnedMesh = Object.extend(THREE.Mesh, { (geometry, materials) { // call the superclass constructor THREE.Mesh.call(this, geometry, materials); // initialize instance properties this.identityMatrix = new THREE.Matrix4(); this.bones = []; this.boneMatrices = []; // ... } update (camera) { THREE.Mesh.update.call(this); } }); Also such callable objects provide shorter alternative to current function syntax: // shorter than function numbers. filter({ (x) { return x % 2 } }). // maybe single expression can be even shorter like arrow functions ? map({ (x) x * x }). forEach({ (x) { this.add(x) } }, that); Also this would allow interesting APIs similar to those found in clojure: // maps / sets similar like in clojure ? var map = WeakMap(), key = {}, value = {}; map.set(key, value); map(key) // = value key(map) // = value And maybe built-ins could have it for doing `[]` work: // Maybe even non-magical replacement for `[]` [ 'a', 'b', 'c' ](1) // = 'b' ({ a: 1, b: 2 })('a') // = 1 ('b')({ a: 1, b: 2 }) // = 2 Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ ___ es-discuss mailing list es-discuss@mozilla.org (mailto:es-discuss@mozilla.org) https://mail.mozilla.org/listinfo/es-discuss -- Dr. Axel Rauschmayer a...@rauschma.de (mailto:a...@rauschma.de) home: rauschma.de (http://rauschma.de)twitter: twitter.com/rauschma (http://twitter.com/rauschma) blog: 2ality.com (http://2ality.com) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss