Proposal: named and bound deconstructions

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

Proposal: named and bound deconstructions

Michael Luder-Rosefield
Deconstructions are great, but have some pain points I'd like to address.

Named deconstructions

When deconstructing elements of an object/array, you lose any reference to the object itself. That reference is useful, not only in the trivial way of being able to simply use it as per normal, but to clarify intent.

```
const someMiddlewareFn = (original, updated, next) => {
  const [ { name }, { name: newName } ] = [ original, updated ]; // any useful deconstructions
  if (name !== newName) { // do stuff }
  return next(original, updated);
}
```
In that example we can't deconstruct `original` or `updated` in the parameter definition, because we have to keep references to them to pass to `next`; we have to do it in the function body, instead. 

By keeping the named parameters, though, we glean more information as to the intent of the function: `original` and `updated` directly imply that we're comparing state changes. 

There might also be occasions when we want to do something like this:

```
const { bar } = foo,
      { baz, blah } = bar;
```

Here, we might find it useful to get deconstructed references to both `bar` and its properties `baz` and `blah`, but we have to do it in two steps.

I propose that we use a symbol to signify that we wish to keep a reference, in passing. We should also allow for renaming, which is made slightly awkward because the current renaming syntax prevents further deconstruction.

Suggestion (using !-prefix)

```
const { !bar: { baz, blah } } = foo, // no renaming
      { bar: !myBar : { baz, blah } } = foo, // renaming

     someMiddlewareFn = (!original: { name }, !updated: { name: newName }, next) => {
        if (name !== newName) { // do stuff }
        return next(original, updated);
      
```
I think that this should be clear to interpret for both coders and JS engines.

Bound deconstructions

Some methods rely on their context being bound to their containers, and require extra binding faff if you want to extract them; this is the pain-point area that the binding operator proposal https://github.com/tc39/proposal-bind-operator is intended to address.

My 2nd suggestion is that we co-opt its `::` syntax for use in deconstructions:

```
const { ::foo } = bar; 
// equivalent to 
// const foo = bar.foo.bind(bar)
```

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

Re: Proposal: named and bound deconstructions

Isiah Meadows-2
What can this do that a second variable declaration can't, apart from
the auto-binding syntax (which already feels a little more like a
tack-on feature rather than something that fits)? And beyond a "that's
nice" kind of thing, how would this bring substantial benefit to the
programmer?
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Jan 24, 2018 at 7:35 AM, Michael Rosefield
<[hidden email]> wrote:

> Deconstructions are great, but have some pain points I'd like to address.
>
> Named deconstructions
>
> When deconstructing elements of an object/array, you lose any reference to
> the object itself. That reference is useful, not only in the trivial way of
> being able to simply use it as per normal, but to clarify intent.
>
> ```
> const someMiddlewareFn = (original, updated, next) => {
>   const [ { name }, { name: newName } ] = [ original, updated ]; // any
> useful deconstructions
>   if (name !== newName) { // do stuff }
>   return next(original, updated);
> }
> ```
> In that example we can't deconstruct `original` or `updated` in the
> parameter definition, because we have to keep references to them to pass to
> `next`; we have to do it in the function body, instead.
>
> By keeping the named parameters, though, we glean more information as to the
> intent of the function: `original` and `updated` directly imply that we're
> comparing state changes.
>
> There might also be occasions when we want to do something like this:
>
> ```
> const { bar } = foo,
>       { baz, blah } = bar;
> ```
>
> Here, we might find it useful to get deconstructed references to both `bar`
> and its properties `baz` and `blah`, but we have to do it in two steps.
>
> I propose that we use a symbol to signify that we wish to keep a reference,
> in passing. We should also allow for renaming, which is made slightly
> awkward because the current renaming syntax prevents further deconstruction.
>
> Suggestion (using !-prefix)
>
> ```
> const { !bar: { baz, blah } } = foo, // no renaming
>       { bar: !myBar : { baz, blah } } = foo, // renaming
>
>      someMiddlewareFn = (!original: { name }, !updated: { name: newName },
> next) => {
>         if (name !== newName) { // do stuff }
>         return next(original, updated);
>
> ```
> I think that this should be clear to interpret for both coders and JS
> engines.
>
> Bound deconstructions
>
> Some methods rely on their context being bound to their containers, and
> require extra binding faff if you want to extract them; this is the
> pain-point area that the binding operator proposal
> https://github.com/tc39/proposal-bind-operator is intended to address.
>
> My 2nd suggestion is that we co-opt its `::` syntax for use in
> deconstructions:
>
> ```
> const { ::foo } = bar;
> // equivalent to
> // const foo = bar.foo.bind(bar)
> ```
>
> _______________________________________________
> 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: named and bound deconstructions

Michael Luder-Rosefield
Well, deconstruction is already mostly just syntactic sugar to accomplish related things in a single, concise, declarative step; this seems like a natural extension of that philosophy.

Why add extra steps like below when you don't have to? I want JS to be as expressive as possible.
```
const { foo, bar, baz } = obj;
[ foo, bar, baz ].forEach(fn => fn.bind(obj);
// VS
const { ::foo, ::bar, ::baz } = obj;
```

On Wed, 24 Jan 2018 at 13:59 Isiah Meadows <[hidden email]> wrote:
What can this do that a second variable declaration can't, apart from
the auto-binding syntax (which already feels a little more like a
tack-on feature rather than something that fits)? And beyond a "that's
nice" kind of thing, how would this bring substantial benefit to the
programmer?
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Jan 24, 2018 at 7:35 AM, Michael Rosefield
<[hidden email]> wrote:
> Deconstructions are great, but have some pain points I'd like to address.
>
> Named deconstructions
>
> When deconstructing elements of an object/array, you lose any reference to
> the object itself. That reference is useful, not only in the trivial way of
> being able to simply use it as per normal, but to clarify intent.
>
> ```
> const someMiddlewareFn = (original, updated, next) => {
>   const [ { name }, { name: newName } ] = [ original, updated ]; // any
> useful deconstructions
>   if (name !== newName) { // do stuff }
>   return next(original, updated);
> }
> ```
> In that example we can't deconstruct `original` or `updated` in the
> parameter definition, because we have to keep references to them to pass to
> `next`; we have to do it in the function body, instead.
>
> By keeping the named parameters, though, we glean more information as to the
> intent of the function: `original` and `updated` directly imply that we're
> comparing state changes.
>
> There might also be occasions when we want to do something like this:
>
> ```
> const { bar } = foo,
>       { baz, blah } = bar;
> ```
>
> Here, we might find it useful to get deconstructed references to both `bar`
> and its properties `baz` and `blah`, but we have to do it in two steps.
>
> I propose that we use a symbol to signify that we wish to keep a reference,
> in passing. We should also allow for renaming, which is made slightly
> awkward because the current renaming syntax prevents further deconstruction.
>
> Suggestion (using !-prefix)
>
> ```
> const { !bar: { baz, blah } } = foo, // no renaming
>       { bar: !myBar : { baz, blah } } = foo, // renaming
>
>      someMiddlewareFn = (!original: { name }, !updated: { name: newName },
> next) => {
>         if (name !== newName) { // do stuff }
>         return next(original, updated);
>
> ```
> I think that this should be clear to interpret for both coders and JS
> engines.
>
> Bound deconstructions
>
> Some methods rely on their context being bound to their containers, and
> require extra binding faff if you want to extract them; this is the
> pain-point area that the binding operator proposal
> https://github.com/tc39/proposal-bind-operator is intended to address.
>
> My 2nd suggestion is that we co-opt its `::` syntax for use in
> deconstructions:
>
> ```
> const { ::foo } = bar;
> // equivalent to
> // const foo = bar.foo.bind(bar)
> ```
>
> _______________________________________________
> 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: named and bound deconstructions

Jerry Schulteis
In reply to this post by Michael Luder-Rosefield
I don't think declaring and destructuring formal parameters all at once improves clarity.
Once you get beyond a toy example, the parameter list, like a sentence with many phrases, becomes awkward, causing readers difficulty in following the meaning.
Technical writing guidelines include the use of concise sentences.
I opine that this guideline applies to code as well.

Your proposed syntax puts the reference to the whole on the left and the destructuring pattern on the right, the opposite of destructuring assignment.

The existing meaning of the exclamation mark is to negate the meaning of what follows.
That seems an odd choice to overload with the meaning "keep a reference".
C++ uses the ampersand for declaring a reference. Not everyone knows C++, but at least it has some basis in an existing language.

If I felt this was needed, my version would look like this:
```
const someMiddlewareFn = ({name} &original, {name: newName} &updated, next) => {
```

However, I like to think of ECMAScript as somewhere near the happy medium on a programming language continuum that puts the terseness of APL at one extreme and the verbosity of COBOL on the other. I think this is an unnecessary nudge in the terse direction.

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

Re: Proposal: named and bound deconstructions

Isiah Meadows-2
In reply to this post by Michael Luder-Rosefield
I'm just not convinced it adds anything substantial. Destructuring
made it possible to flatten 3-5 lines to 1, along with the ability to
provide defaults. This just:

1. Lets you give a name to a temporary object, when an extra statement
does this for you. (It's rare to want to alias more than one thing.)
2. Let's you auto-bind a property when extracting it. (This could be
suggested in an issue in the [bind operator's repo][1], and is more
relevant there.)

Also, with recent talks about [making operator-bound callbacks
idempotent in the bind operator proposal][2], that could reduce bound
methods to just a simple property-like "access".

[1]: https://github.com/tc39/proposal-bind-operator.
[2]: https://github.com/tc39/proposal-bind-operator/issues/46#issuecomment-359248949
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Wed, Jan 24, 2018 at 10:25 AM, Michael Rosefield
<[hidden email]> wrote:

> Well, deconstruction is already mostly just syntactic sugar to accomplish
> related things in a single, concise, declarative step; this seems like a
> natural extension of that philosophy.
>
> Why add extra steps like below when you don't have to? I want JS to be as
> expressive as possible.
> ```
> const { foo, bar, baz } = obj;
> [ foo, bar, baz ].forEach(fn => fn.bind(obj);
> // VS
> const { ::foo, ::bar, ::baz } = obj;
> ```
>
> On Wed, 24 Jan 2018 at 13:59 Isiah Meadows <[hidden email]> wrote:
>>
>> What can this do that a second variable declaration can't, apart from
>> the auto-binding syntax (which already feels a little more like a
>> tack-on feature rather than something that fits)? And beyond a "that's
>> nice" kind of thing, how would this bring substantial benefit to the
>> programmer?
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>>
>>
>> On Wed, Jan 24, 2018 at 7:35 AM, Michael Rosefield
>> <[hidden email]> wrote:
>> > Deconstructions are great, but have some pain points I'd like to
>> > address.
>> >
>> > Named deconstructions
>> >
>> > When deconstructing elements of an object/array, you lose any reference
>> > to
>> > the object itself. That reference is useful, not only in the trivial way
>> > of
>> > being able to simply use it as per normal, but to clarify intent.
>> >
>> > ```
>> > const someMiddlewareFn = (original, updated, next) => {
>> >   const [ { name }, { name: newName } ] = [ original, updated ]; // any
>> > useful deconstructions
>> >   if (name !== newName) { // do stuff }
>> >   return next(original, updated);
>> > }
>> > ```
>> > In that example we can't deconstruct `original` or `updated` in the
>> > parameter definition, because we have to keep references to them to pass
>> > to
>> > `next`; we have to do it in the function body, instead.
>> >
>> > By keeping the named parameters, though, we glean more information as to
>> > the
>> > intent of the function: `original` and `updated` directly imply that
>> > we're
>> > comparing state changes.
>> >
>> > There might also be occasions when we want to do something like this:
>> >
>> > ```
>> > const { bar } = foo,
>> >       { baz, blah } = bar;
>> > ```
>> >
>> > Here, we might find it useful to get deconstructed references to both
>> > `bar`
>> > and its properties `baz` and `blah`, but we have to do it in two steps.
>> >
>> > I propose that we use a symbol to signify that we wish to keep a
>> > reference,
>> > in passing. We should also allow for renaming, which is made slightly
>> > awkward because the current renaming syntax prevents further
>> > deconstruction.
>> >
>> > Suggestion (using !-prefix)
>> >
>> > ```
>> > const { !bar: { baz, blah } } = foo, // no renaming
>> >       { bar: !myBar : { baz, blah } } = foo, // renaming
>> >
>> >      someMiddlewareFn = (!original: { name }, !updated: { name: newName
>> > },
>> > next) => {
>> >         if (name !== newName) { // do stuff }
>> >         return next(original, updated);
>> >
>> > ```
>> > I think that this should be clear to interpret for both coders and JS
>> > engines.
>> >
>> > Bound deconstructions
>> >
>> > Some methods rely on their context being bound to their containers, and
>> > require extra binding faff if you want to extract them; this is the
>> > pain-point area that the binding operator proposal
>> > https://github.com/tc39/proposal-bind-operator is intended to address.
>> >
>> > My 2nd suggestion is that we co-opt its `::` syntax for use in
>> > deconstructions:
>> >
>> > ```
>> > const { ::foo } = bar;
>> > // equivalent to
>> > // const foo = bar.foo.bind(bar)
>> > ```
>> >
>> > _______________________________________________
>> > 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: named and bound deconstructions

Bob Myers
Destructuring made it possible to flatten 3-5 lines to 1, along with the ability to provide defaults. 

Yet, as an aside, this "principle" of "flattening" being a sufficient or at least necessary condition for syntax proposals, is itself not applied consistently, as seen in the "rejection" (if lack of positive response on this mailing list can be deemed "rejection") of the proposed property-picking syntax, which allows one to replace three lines

```
const {a, b} = foo;
const {c, d} = bar;
return {a, b, c, d};
```

with one:

```
return { {a, b} = foo, {c, d} = bar };
```

Actually, by the way, destructuring is of course about more than brevity. It mitigates a common type of typo-related bug:

```
const misspelledProp = foo.mispeledProp;
```

Bob


On Thu, Jan 25, 2018 at 10:02 AM, Isiah Meadows <[hidden email]> wrote:
I'm just not convinced it adds anything substantial. Destructuring
made it possible to flatten 3-5 lines to 1, along with the ability to
provide defaults. This just:

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

Re: Re: Proposal: named and bound deconstructions

Darien Valentine
In reply to this post by Michael Luder-Rosefield
> There might also be occasions when we want to do something like this:
>    const { bar } = foo,
>          { baz, blah } = bar;
>
> Here, we might find it useful to get deconstructed references to both bar and its properties baz and blah, but we have to do it in two steps.

Unless I’m misunderstanding what you mean, doing this in a single pattern is already accounted for:

    const { bar, bar: { baz, blah } } = foo;

There’s no restriction on the number of times the key appears.

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