Reified lvalue (was: Re: Extensible destructuring proposal)

# Herby Vojčík (9 years ago)

Bergi wrote:

Samuel Hapák schrieb:

The main idea is, that if object defines Symbol.get method, it gets used to access properties of object instead of [] when destructuring.

Aw, when I read "extensible destructuring" I had hoped to see an extension to the destructuring syntax, not to see how semantics of destructuring objects are changed.

What do you think about extractor functions, like in Scala www.scala-lang.org/old/node/112? Instead of unapply or unapplySeq methods we'd probably use an @@extractor (Symbol.extractor) method or so, allowing us to do

let Map({a, b, c}) = myMap;

let List(a, b, c) = myList;

const Map({author: Map({name: {first, last}, birthdate})}) = book;

which would desugar to

let [{a, b, c}] = MapSymbol.extractor;

let [a, b, c] = ListSymbol.extractor;

const [{author: __author}] = MapSymbol.extractor; const [{name: {first, last}, birthdate}] = MapSymbol.extractor;

where each extractor method would return an Iterable that is assigned to the "arguments" of the extractor. (A Proxy to lazily destructure object literals in there is a good idea, thanks @Claude).

This would even allow us to call functions on destructuring, think about module imports:

// a.js export default function factory(options) { … return moduleInstance; }

// b.js const NoOptions = { Symbol.extractor { return [factory()]; } }; const WithOptions = (...args) => ({ Symbol.extractor { return [factory(...args)]; } });

import NoOptions(A) from "a"; import WithOptions("config")(A) from "a"; // A === moduleInstance

What do you think about that?

Nice, but as Samuel mentioned, you need to actually transform the data so it can be fed to stock destructurer.

What I came up is the idea of "reified lvalue", the object that describes the (complex, destucturing) lvalue used for assignment (for example as the list of simple expression assignments, internally); and that such object could be transformed.

Like (very rough examples; just an idea, not the spec):

let a = 4;

outer a <- input

let {a,c:{b}} = foo;

outer a <- input.a tmp0 <- input.c outer b <- tmp0.b

let {a,c:Map({b})} = foo;

Map[Symbol.lvalue] gets "outer b <- input.b" and transforms it to "outer b <- input.get('b')", so the result would be:

outer a <- input.a tmp0 <- input.c outer b <- tmp0.get('b')

let Map(a,c:Map({b})) = foo;

Map[Symbol.lvalue] get the above descriptor and transforms it to

outer a <- input.get('a') tmp0 <- input.get('c') outer b <- tmp.get('b')

If things like Map[Symbol.lvalue] would be frozen (or just speculatively supposed not to be mutated), this can as well be done at compile time, so the resulting code could stay fast.

# Isiah Meadows (9 years ago)

I know this is pointless bikeshedding, but that particular operator conflicts with a current valid production.

// These are synonymous, and are
// valid statements
tmp0 <- input.get('c')
tmp0 < (-input.get('c'))
# Isiah Meadows (9 years ago)

No problem. I was aware of the intent. Also, I cc'd the list for you.

P.S. I did state it as pointless bikeshedding, so I did kinda leave myself open for criticism for merely bringing it up.