Proposal: Symbol.templateTag

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal: Symbol.templateTag

Alexander Jones
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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Symbol.templateTag

Mark S. Miller-2
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 <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Symbol.templateTag

Alexander Jones
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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Symbol.templateTag

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Symbol.templateTag

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Symbol.templateTag

Alexander Jones
In reply to this post by Alexander Jones
As promised (to myself!) I've written a stage-0.


Your feedback is greatly appreciated.

Thanks

On 18 November 2016 at 00:30, Alexander Jones <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
    Cheers,
    --MarkM



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss