Proposal: Symbol.templateTag
I have run into this myself. It is a real problem, and I like the nature of your proposed solution. But I don't understand how it might break the web. If Symbol.templateTag is a new symbol, guaranteed unequal to any prior value, how can introducing it, and new behavior conditional on it, change any existing behavior?
Hi Alexander, I have run into this myself. It is a real problem, and I like the nature of your proposed solution. But I don't understand how it might break the web. If Symbol.templateTag is a new symbol, guaranteed unequal to any prior value, how can introducing it, and new behavior conditional on it, change any existing behavior? On Wed, Nov 16, 2016 at 5:02 PM, Alexander Jones <alex at weej.com> wrote: > Hi es-discuss! > > Template tags are a great feature with many novel applications, IMO > approaching macro-level expressiveness. But due to their nature in this > context, it's helpful if tags are named quite tersely. Unfortunately, if > you have existing API, this can be challenging. > > Let's say I have a DSL (domain-specific language), and I *may*, unsafely, > generate typed snippets of code containing that DSL like so: > > ```js > function dsl(code: string) { > // `code` MUST be well-formed > } > > const someStatement = dsl("val foo = " + dslEncode(foo)); > ``` > > Let's say I'd like to add support in my library for ES6 clients such that > they can do: > > ```js > const someStatement = dsl`val foo = ${foo}`; > ``` > > where the `dsl` template tag would be implemented such that `dslEncode` is > used on each interpolated expression. > > Unfortunately, the `dsl` function's arguments are already defined and > can't be changed. I'd need a new name, like `dsl.tag`, which would end up > being a fair bit more verbose. > > Would it be possible, at this point, to introduce a new behaviour into ES > such that instead of merely calling the tag object, the implementation > first checks for a `Symbol.templateTag` property on the tag object, and if > it exists, it is invoked? I'd guess this can't Break The Web because no-one > can realistically be using an existing function as a template tag if it was > not already designed for it. > > ```js > const someStatement = dsl`val foo = ${foo}`; > // desugars to, approximately > const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", ""], > foo); > ``` > > To be honest, I am kind of surprised it wasn't already implemented like > this, but maybe there were performance concerns with the branching. > Interested in your thoughts. > > Thanks > > Alex > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -- Cheers, --MarkM -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161116/c5878d87/attachment.html>
OK, I was thinking about this incorrectly and I think you're right - it doesn't Break The Web. It's exactly the same as when @@isConcatSpreadable and @@toStringTag were introduced, as far as I can tell.
If no-one has any obvious objections to save me the effort, I'll try to write up a stage 0 this weekend.
OK, I was thinking about this incorrectly and I think you're right - it doesn't Break The Web. It's exactly the same as when @@isConcatSpreadable and @@toStringTag were introduced, as far as I can tell. If no-one has any obvious objections to save me the effort, I'll try to write up a stage 0 this weekend. Thanks On 17 November 2016 at 04:58, Mark S. Miller <erights at google.com> wrote: > Hi Alexander, I have run into this myself. It is a real problem, and I > like the nature of your proposed solution. But I don't understand how it > might break the web. If Symbol.templateTag is a new symbol, guaranteed > unequal to any prior value, how can introducing it, and new behavior > conditional on it, change any existing behavior? > > > > > On Wed, Nov 16, 2016 at 5:02 PM, Alexander Jones <alex at weej.com> wrote: > >> Hi es-discuss! >> >> Template tags are a great feature with many novel applications, IMO >> approaching macro-level expressiveness. But due to their nature in this >> context, it's helpful if tags are named quite tersely. Unfortunately, if >> you have existing API, this can be challenging. >> >> Let's say I have a DSL (domain-specific language), and I *may*, unsafely, >> generate typed snippets of code containing that DSL like so: >> >> ```js >> function dsl(code: string) { >> // `code` MUST be well-formed >> } >> >> const someStatement = dsl("val foo = " + dslEncode(foo)); >> ``` >> >> Let's say I'd like to add support in my library for ES6 clients such that >> they can do: >> >> ```js >> const someStatement = dsl`val foo = ${foo}`; >> ``` >> >> where the `dsl` template tag would be implemented such that `dslEncode` >> is used on each interpolated expression. >> >> Unfortunately, the `dsl` function's arguments are already defined and >> can't be changed. I'd need a new name, like `dsl.tag`, which would end up >> being a fair bit more verbose. >> >> Would it be possible, at this point, to introduce a new behaviour into ES >> such that instead of merely calling the tag object, the implementation >> first checks for a `Symbol.templateTag` property on the tag object, and if >> it exists, it is invoked? I'd guess this can't Break The Web because no-one >> can realistically be using an existing function as a template tag if it was >> not already designed for it. >> >> ```js >> const someStatement = dsl`val foo = ${foo}`; >> // desugars to, approximately >> const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", ""], >> foo); >> ``` >> >> To be honest, I am kind of surprised it wasn't already implemented like >> this, but maybe there were performance concerns with the branching. >> Interested in your thoughts. >> >> Thanks >> >> Alex >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > > -- > Cheers, > --MarkM > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161118/c936f970/attachment.html>
I'm not fully sure I understand ... instead of:
const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (i ?
rest[i-1] : '') + c);
you are looking for something similar ?
const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (
i ? (dsl[Symbol.templateTag] || String)(rest[i-1]) : ''
) + c);
if that's the case, is Symbol.templateTag
really needed ?
It looks to me it's possible to define your own behavior through your own transformer already and this proposal easily brings parsing-method clashing in the plate.
Or maybe not ... like I've said, I haven't fully understood the issue.
Thanks for any sort of extra clarification.
I'm not fully sure I understand ... instead of: ```js const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (i ? rest[i-1] : '') + c); ``` you are looking for something similar ? ```js const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + ( i ? (dsl[Symbol.templateTag] || String)(rest[i-1]) : '' ) + c); ``` if that's the case, is `Symbol.templateTag` really needed ? It looks to me it's possible to define your own behavior through your own transformer already and this proposal easily brings parsing-method clashing in the plate. Or maybe not ... like I've said, I haven't fully understood the issue. Thanks for any sort of extra clarification. Regards On Fri, Nov 18, 2016 at 12:30 AM, Alexander Jones <alex at weej.com> wrote: > OK, I was thinking about this incorrectly and I think you're right - it > doesn't Break The Web. It's exactly the same as when @@isConcatSpreadable > and @@toStringTag were introduced, as far as I can tell. > > If no-one has any obvious objections to save me the effort, I'll try to > write up a stage 0 this weekend. > > Thanks > > > > On 17 November 2016 at 04:58, Mark S. Miller <erights at google.com> wrote: > >> Hi Alexander, I have run into this myself. It is a real problem, and I >> like the nature of your proposed solution. But I don't understand how it >> might break the web. If Symbol.templateTag is a new symbol, guaranteed >> unequal to any prior value, how can introducing it, and new behavior >> conditional on it, change any existing behavior? >> >> >> >> >> On Wed, Nov 16, 2016 at 5:02 PM, Alexander Jones <alex at weej.com> wrote: >> >>> Hi es-discuss! >>> >>> Template tags are a great feature with many novel applications, IMO >>> approaching macro-level expressiveness. But due to their nature in this >>> context, it's helpful if tags are named quite tersely. Unfortunately, if >>> you have existing API, this can be challenging. >>> >>> Let's say I have a DSL (domain-specific language), and I *may*, >>> unsafely, generate typed snippets of code containing that DSL like so: >>> >>> ```js >>> function dsl(code: string) { >>> // `code` MUST be well-formed >>> } >>> >>> const someStatement = dsl("val foo = " + dslEncode(foo)); >>> ``` >>> >>> Let's say I'd like to add support in my library for ES6 clients such >>> that they can do: >>> >>> ```js >>> const someStatement = dsl`val foo = ${foo}`; >>> ``` >>> >>> where the `dsl` template tag would be implemented such that `dslEncode` >>> is used on each interpolated expression. >>> >>> Unfortunately, the `dsl` function's arguments are already defined and >>> can't be changed. I'd need a new name, like `dsl.tag`, which would end up >>> being a fair bit more verbose. >>> >>> Would it be possible, at this point, to introduce a new behaviour into >>> ES such that instead of merely calling the tag object, the implementation >>> first checks for a `Symbol.templateTag` property on the tag object, and if >>> it exists, it is invoked? I'd guess this can't Break The Web because no-one >>> can realistically be using an existing function as a template tag if it was >>> not already designed for it. >>> >>> ```js >>> const someStatement = dsl`val foo = ${foo}`; >>> // desugars to, approximately >>> const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", >>> ""], foo); >>> ``` >>> >>> To be honest, I am kind of surprised it wasn't already implemented like >>> this, but maybe there were performance concerns with the branching. >>> Interested in your thoughts. >>> >>> Thanks >>> >>> Alex >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> >> -- >> Cheers, >> --MarkM >> > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161118/85d53a51/attachment.html>
fix: forgot of course i would never be 0
`const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + rest[i-1]
- c);`
VS
const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (dsl[Symbol.templateTag] || String)(rest[i-1]) + c);
fix: forgot of course i would never be 0 `const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + rest[i-1] + c);` VS `const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (dsl[Symbol.templateTag] || String)(rest[i-1]) + c);` On Fri, Nov 18, 2016 at 12:56 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote: > I'm not fully sure I understand ... instead of: > > ```js > const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + (i ? > rest[i-1] : '') + c); > ``` > > you are looking for something similar ? > > ```js > const dsl = (chunks, ...rest) => chunks.reduce((s, c, i) => s + ( > i ? (dsl[Symbol.templateTag] || String)(rest[i-1]) : '' > ) + c); > ``` > > if that's the case, is `Symbol.templateTag` really needed ? > > It looks to me it's possible to define your own behavior through your own > transformer already and this proposal easily brings parsing-method clashing > in the plate. > > Or maybe not ... like I've said, I haven't fully understood the issue. > > Thanks for any sort of extra clarification. > > Regards > > > On Fri, Nov 18, 2016 at 12:30 AM, Alexander Jones <alex at weej.com> wrote: > >> OK, I was thinking about this incorrectly and I think you're right - it >> doesn't Break The Web. It's exactly the same as when @@isConcatSpreadable >> and @@toStringTag were introduced, as far as I can tell. >> >> If no-one has any obvious objections to save me the effort, I'll try to >> write up a stage 0 this weekend. >> >> Thanks >> >> >> >> On 17 November 2016 at 04:58, Mark S. Miller <erights at google.com> wrote: >> >>> Hi Alexander, I have run into this myself. It is a real problem, and I >>> like the nature of your proposed solution. But I don't understand how it >>> might break the web. If Symbol.templateTag is a new symbol, guaranteed >>> unequal to any prior value, how can introducing it, and new behavior >>> conditional on it, change any existing behavior? >>> >>> >>> >>> >>> On Wed, Nov 16, 2016 at 5:02 PM, Alexander Jones <alex at weej.com> wrote: >>> >>>> Hi es-discuss! >>>> >>>> Template tags are a great feature with many novel applications, IMO >>>> approaching macro-level expressiveness. But due to their nature in this >>>> context, it's helpful if tags are named quite tersely. Unfortunately, if >>>> you have existing API, this can be challenging. >>>> >>>> Let's say I have a DSL (domain-specific language), and I *may*, >>>> unsafely, generate typed snippets of code containing that DSL like so: >>>> >>>> ```js >>>> function dsl(code: string) { >>>> // `code` MUST be well-formed >>>> } >>>> >>>> const someStatement = dsl("val foo = " + dslEncode(foo)); >>>> ``` >>>> >>>> Let's say I'd like to add support in my library for ES6 clients such >>>> that they can do: >>>> >>>> ```js >>>> const someStatement = dsl`val foo = ${foo}`; >>>> ``` >>>> >>>> where the `dsl` template tag would be implemented such that `dslEncode` >>>> is used on each interpolated expression. >>>> >>>> Unfortunately, the `dsl` function's arguments are already defined and >>>> can't be changed. I'd need a new name, like `dsl.tag`, which would end up >>>> being a fair bit more verbose. >>>> >>>> Would it be possible, at this point, to introduce a new behaviour into >>>> ES such that instead of merely calling the tag object, the implementation >>>> first checks for a `Symbol.templateTag` property on the tag object, and if >>>> it exists, it is invoked? I'd guess this can't Break The Web because no-one >>>> can realistically be using an existing function as a template tag if it was >>>> not already designed for it. >>>> >>>> ```js >>>> const someStatement = dsl`val foo = ${foo}`; >>>> // desugars to, approximately >>>> const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", >>>> ""], foo); >>>> ``` >>>> >>>> To be honest, I am kind of surprised it wasn't already implemented like >>>> this, but maybe there were performance concerns with the branching. >>>> Interested in your thoughts. >>>> >>>> Thanks >>>> >>>> Alex >>>> >>>> _______________________________________________ >>>> es-discuss mailing list >>>> es-discuss at mozilla.org >>>> https://mail.mozilla.org/listinfo/es-discuss >>>> >>>> >>> >>> >>> -- >>> Cheers, >>> --MarkM >>> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161118/b8766376/attachment-0001.html>
As promised (to myself!) I've written a stage-0.
alex-weej/es-symbol-template-tag
Your feedback is greatly appreciated.
As promised (to myself!) I've written a stage-0. https://github.com/alex-weej/es-symbol-template-tag Your feedback is greatly appreciated. Thanks On 18 November 2016 at 00:30, Alexander Jones <alex at weej.com> wrote: > OK, I was thinking about this incorrectly and I think you're right - it > doesn't Break The Web. It's exactly the same as when @@isConcatSpreadable > and @@toStringTag were introduced, as far as I can tell. > > If no-one has any obvious objections to save me the effort, I'll try to > write up a stage 0 this weekend. > > Thanks > > > > On 17 November 2016 at 04:58, Mark S. Miller <erights at google.com> wrote: > >> Hi Alexander, I have run into this myself. It is a real problem, and I >> like the nature of your proposed solution. But I don't understand how it >> might break the web. If Symbol.templateTag is a new symbol, guaranteed >> unequal to any prior value, how can introducing it, and new behavior >> conditional on it, change any existing behavior? >> >> >> >> >> On Wed, Nov 16, 2016 at 5:02 PM, Alexander Jones <alex at weej.com> wrote: >> >>> Hi es-discuss! >>> >>> Template tags are a great feature with many novel applications, IMO >>> approaching macro-level expressiveness. But due to their nature in this >>> context, it's helpful if tags are named quite tersely. Unfortunately, if >>> you have existing API, this can be challenging. >>> >>> Let's say I have a DSL (domain-specific language), and I *may*, >>> unsafely, generate typed snippets of code containing that DSL like so: >>> >>> ```js >>> function dsl(code: string) { >>> // `code` MUST be well-formed >>> } >>> >>> const someStatement = dsl("val foo = " + dslEncode(foo)); >>> ``` >>> >>> Let's say I'd like to add support in my library for ES6 clients such >>> that they can do: >>> >>> ```js >>> const someStatement = dsl`val foo = ${foo}`; >>> ``` >>> >>> where the `dsl` template tag would be implemented such that `dslEncode` >>> is used on each interpolated expression. >>> >>> Unfortunately, the `dsl` function's arguments are already defined and >>> can't be changed. I'd need a new name, like `dsl.tag`, which would end up >>> being a fair bit more verbose. >>> >>> Would it be possible, at this point, to introduce a new behaviour into >>> ES such that instead of merely calling the tag object, the implementation >>> first checks for a `Symbol.templateTag` property on the tag object, and if >>> it exists, it is invoked? I'd guess this can't Break The Web because no-one >>> can realistically be using an existing function as a template tag if it was >>> not already designed for it. >>> >>> ```js >>> const someStatement = dsl`val foo = ${foo}`; >>> // desugars to, approximately >>> const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", >>> ""], foo); >>> ``` >>> >>> To be honest, I am kind of surprised it wasn't already implemented like >>> this, but maybe there were performance concerns with the branching. >>> Interested in your thoughts. >>> >>> Thanks >>> >>> Alex >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >> >> >> -- >> Cheers, >> --MarkM >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161120/521821c0/attachment.html>
discuss!
Template tags are a great feature with many novel applications, IMO approaching macro-level expressiveness. But due to their nature in this context, it's helpful if tags are named quite tersely. Unfortunately, if you have existing API, this can be challenging.
Let's say I have a DSL (domain-specific language), and I may, unsafely, generate typed snippets of code containing that DSL like so:
function dsl(code: string) { // `code` MUST be well-formed } const someStatement = dsl("val foo = " + dslEncode(foo));
Let's say I'd like to add support in my library for ES6 clients such that they can do:
const someStatement = dsl`val foo = ${foo}`;
where the
dsl
template tag would be implemented such thatdslEncode
is used on each interpolated expression.Unfortunately, the
dsl
function's arguments are already defined and can't be changed. I'd need a new name, likedsl.tag
, which would end up being a fair bit more verbose.Would it be possible, at this point, to introduce a new behaviour into ES such that instead of merely calling the tag object, the implementation first checks for a
Symbol.templateTag
property on the tag object, and if it exists, it is invoked? I'd guess this can't Break The Web because no-one can realistically be using an existing function as a template tag if it was not already designed for it.const someStatement = dsl`val foo = ${foo}`; // desugars to, approximately const someStatement = (dsl[Symbol.templateTag] || dsl)(["val foo =", ""], foo);
To be honest, I am kind of surprised it wasn't already implemented like this, but maybe there were performance concerns with the branching. Interested in your thoughts.
Thanks
Alex