Destructuring by &reference

Andrea Giammarchi andrea.giammarchi at gmail.com
Thu Mar 4 08:42:51 UTC 2021


> How will you prevent the passing of the object down the pipe?

```js
const downThePipe = ({&source}) => {
  // you can read source
  source;
  // you can set source
  source = 'blah';
  // you can't know where source comes from
  // but you could propagate that reference further
  evenFurtherDown({&source, any: 'value'}, Math.random());
};

downThePipe({
  secret: 'nothing out there can reach me',
  get source() { 'this object'; },
  set source(value) {
    console.log('hello', value, this.secret);
  }
});
```

You can pass objects already in JS so this changes nothing in terms of
logic, except the callback has a way to signal reactive properties or
retrieved methods.

Any boilerplate with Proxies would be slower and more convoluted, so this
syntax simplieis all the code you wrote via an explicit intent: the
callback would like to invoke, or update an accessor, of the given object,
without holding, or having, the whole object in its scope.

I hope this explains a bit better why I think this feature would be
extremely cool. Polyfills won't need to do much, code remains short and
clean, accessors/reactive properties becomes instantly clear (they say
accessors are a footgun, here we're flagging these for better awareness)
and methods can be invoked with the right context too, without needing
whole objects references around.


On Wed, Mar 3, 2021 at 9:03 PM Augusto Moura <augusto.borgesm at gmail.com>
wrote:

> > that's basically the entirety of the syntax sugar proposals since
> ES2015, right?
>
> Definitely no, but talking about the syntax additions since ES2015, they
> are in one or more of the categories below:
> - avoid known footguns in the language (arrow functions and lexical this,
> classes and prototype, let/const and block scoping, nullish coalescing
> operator, etc.)
> - syntax sugars with strong community feedback AND battle proven prior art
> (classes, destructuring, string templates, rest, spread and default
> values, async/await, etc.)
> - introducing or specifying new mechanisms that didn't exist before in
> ecma (modules, classes, varargs, etc.)
>
> > also proxy and globalThis are *really* unrelated to this
>
> Proxy and globalThis (and the `with` statement for that matter), are
> mechanisms of value indirection aside from the "classic" instance properties
>
> >  while leaking objects all over down the pipe is my major concern,
> something this proposal avoids, as no code will have a reference to the
> entirety of the source object, they'll deal with a known property name
> passed by reference, incapable of changing anything else in the source
> object ... so it's rather a signal, than a convention.
>
> How will you prevent the passing of the object down the pipe? You mean the
> reference variable being passed to another function and setting the prop
> into the source object?
> ```js
> function foo(source) {
>   let { &value } = source;
>   value = 'foo';
> }
>
> function second(source) {
>   // You still need to pass the object forward right?
>   foo(source)
>
>   // Or the proposal is something like this
>   let { &value } = source;
>   foo(value);
>   // and then if foo sets the value argument it should reflect in source
> }
> ```
>
> Also the usual way of preventing the "passing the full object down"
> problem is restricting the contract with other functions using a
> wrapper/proxy, a well defined more specific interface or in the readonly
> case just omitting the other properties
>
> ```ts
> // Wrapper way
> class Nameable {
>   constructor(instance) { this.#obj = instance }
>   get name() { return this.#obj.name }
>   set name(newName) { this.#obj.name = newName }
> }
>
> function printName(nameable) {
>   console.log(nameable.name)
>   nameable.name += ' [printed]'
> }
> function foo(source) {
>   printName(new Nameable(source))
> }
> foo({ name: 'foo', type: 'pojo' })
>
> // Well defined contract way (using Typescript, but you could rely on duck
> typing if you trust the good manners of the developers)
> interface Nameable {
>   name: string;
> }
> interface Pojo extends Nameable {
>   type: string;
> }
>
> function printName(nameable: Nameable) {
>   console.log(nameable.name)
>   nameable.name += ' [printed]'
>   // the function still can access the type field by ignoring the typing,
> but at this point this is the least scary thing a developer in a app
> }
> function foo(source: Pojo) {
>   printName(source)
> }
>
> // Omit and readonly way
> function printName(nameable) { /* ... */ }
> function foo(source) {
>   printName(pick(source, ['name']))
> }
> ```
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20210304/2f85c626/attachment-0001.html>


More information about the es-discuss mailing list