<p>Some languages allow you to write something like</p>
<pre><code>x, y, z = (1, 2, 3)
</code></pre>
<p>Which is equivalent to</p>
<pre><code>x = 1
y = 2
z = 3
</code></pre>
<p>What are some of the syntax constructs that exist that perform variable destructuring/unpacking?</p>

<syntax><language-comparison>
What syntax options exist for variable destructuring/unpacking?
CC BY-SA 4.0
2023-05-18T12:48:23.470Z
Generally the syntax for destructuring will mirror the syntax for constructing the same data. So if your language has data structures which can be destructured, then you presumably already have syntax for them.
kaya3
<p>An approach I'd like to see would be a construct that combines new automatic-scope object declarations and initializer-like constructs with a compound statement.  Perhaps something like:</p>
<pre><code>union ( int x=foo-&gt;bar : 4,8, y = baz-&gt;bongo : 3,9;)
{
  ...
}
</code></pre>
<p>The syntax would be identifiable by the opening parenthesis following the <code>union</code> keyword--something that would otherwise be impossible.</p>
<p>The &quot;initializers&quot; would need to be lvalues, optionally followed by a bit width and offset.  Such a syntax would invite a compiler to behave as though the declared identifiers were objects of the indicated type which were loaded any time before their value was used, and written back any time after their value was modified, in any manner consistent with normal &quot;caching&quot; semantics (if a compiler modifies the temporary object, future reads would need to come from that object rather than the original until the change was written back; if the compiler reads and caches the original object, but then modifies the orginal object, it would need to ensure that the cached copy was updated or reloaded before it was used againm etc.).</p>
<p>If two or more initializers are bound to the same side-effect-free lvalue expression, a compiler would have to allow for the possibility that changes to one might affect the other, but such allowance would not be required if lvalue expressions have side effects or don't match each other.</p>
<p>Note that while this construct would be semantically most useful when handlings things like bit fields, it could also allow compilers the freedom to keep an object that would be updated multiple times in a register, and consolidate multiple writes to an object, when doing so would be useful, but allow a compiler to flush such cached objectss in cases where the alternative would be an extra register spill (thus allowing what would be the sequence:</p>
<pre><code>load x into r0
... do some stuff with r0
push r0
... do some stuff that needs to use r0 for some other purpose
... pop r0
store r0 into x
</code></pre>
<p>to be improved by storing r0 into x before the stuff that would use r0 for some other purpose, and avoiding the need to pop it and then store it.</p>

CC BY-SA 4.0
2023-07-02T18:34:44.830Z
2023-07-02T18:34:44.830Z
supercat
<p>For JavaScript, there are two valid syntaxes, depending on what you are destructuring. In both cases they attempt to mirror the data structure they work on:</p>
<h2>Array destructuring</h2>
<p>Uses <code>[ ]</code> to enclose the variables that need to be unpacked and does so <em>positionally</em> - the first variable takes on the first value, the second variable takes on the second value, etc.:</p>
<pre><code>const someArray = [1, 2, 3];
const [x, y, z] = someArray;
</code></pre>
<p>Positions can be skipped via elision - by <em>not</em> supplying a variable:</p>
<pre><code>const someArray = [1, 2, 3];
const [x, , z] = someArray;
</code></pre>
<p>Which is essentially the same as:</p>
<pre><code>const x = someArray[0];
const z = someArray[2];
</code></pre>
<h3>Rest syntax <code>...</code></h3>
<p>The remainder of the unpacked values can be collected into a single array by using the syntax <code>...&lt;variable name&gt;</code>, for example</p>
<pre><code>const someArray = [1, 2, 3];
const [x, ...others] = someArray;
</code></pre>
<p>will have <code>others = [2, 3]</code></p>
<h3>Not just for arrays</h3>
<p>The common name is &quot;array destructuring&quot; but it does not only work on arrays but any iterable. For example sets or generators:</p>
<pre><code>const someSet = new Set().add(1).add(2).add(3);
const [x, y, z] = someSet;
</code></pre>
<pre><code>const someGenerator = function* () {
    yield 1;
    yield 2;
    yield 3;
}
const [x, y, z] = someGenerator();
</code></pre>
<p>In a lot of common cases it is more or less the same whether you use it on arrays or not. However, that is not necessarily correct for all iterables - if consuming an iterable keeps producing values, the array destructuring will keep drawing, rather than only get the same position:</p>
<pre><code>const someArray = [1, 2, 3];
const [x] = someArray;
const [y] = someArray;
const [z] = someArray;
</code></pre>
<p>Will produce <code>x = 1</code>, <code>y = 1</code>, and <code>z = 1</code> because each of them is assigned the first position of the array. Destructuring the array produces a new iterator each time that starts from the start.</p>
<p>While</p>
<pre><code>const someGenerator = function* () {
    yield 1;
    yield 2;
    yield 3;
}

const [x] = someGenerator;
const [y] = someGenerator;
const [z] = someGenerator;
</code></pre>
<p>Will produce <code>x = 1</code>, <code>y = 2</code>, and <code>z = 3</code> because there is one iterator in total that keeps producing values.</p>
<h2>Object destructuring</h2>
<p>Uses <code>{ }</code> to enclose the variables that need to be unpacked and does so <em>by name</em>:</p>
<pre><code>const someObject = {x: 1, y: 2, z: 3 };

const { x, y, z } = someObject;
</code></pre>
<p>Essentially the same as:</p>
<pre><code>const someObject = {x: 1, y: 2, z: 3 };

const x = someObject.x;
const y = someObject.y;
const z = someObject.z;
</code></pre>
<p>The longer form also allows for re-mapping the properties to differently named variables:</p>
<pre><code>const someObject = {x: 1, y: 2, z: 3 };

const { a: x, b: y, c: z } = someObject;
</code></pre>
<p>Essentially the same as:</p>
<pre><code>const someObject = {x: 1, y: 2, z: 3 };

const a = someObject.x;
const b = someObject.y;
const c = someObject.z;
</code></pre>
<h3>Rest syntax <code>...</code></h3>
<p>Very similar to how the array destructuring syntax can use <code>...&lt;variable name&gt;</code> to collect the rest of the unpacked values, the same can be done with object destructuring to collect all key/values that have not been extracted otherwise:</p>
<pre><code>const someObject = {x: 1, y: 2, z: 3 };

const { x, ...others } = someObject;
</code></pre>
<p>will have <code>others = { y: 2, z: 3 }</code></p>
<h2>Combining these</h2>
<p>These can be arbitrarily nested and combined to access any property and value:</p>
<pre><code>const users = [
    { 
        name: &quot;Fred&quot;, 
        userInfo: { likes: &quot;bowling&quot; }, 
        addresses: [&quot;Town of Bedrock&quot;, &quot;some previous address&quot;] 
    }
];

const [
    { 
        name, 
        userInfo: { likes: hobby }, 
        addresses: [lastAddress] 
    }
] = user;
</code></pre>
<p>Will extract: <code>name = &quot;Fred&quot;</code>, <code>hobby = &quot;bowling&quot;</code>, and <code>lastAddress = &quot;Town of Bedrock&quot;</code>.</p>

CC BY-SA 4.0
2023-05-18T13:15:53.633Z
2023-05-18T13:15:53.633Z
VLAZ
CC BY-SA 4.0
2023-05-18T13:48:26.333Z
You can also destructure within function parameters `({ name }) => name`, or use iterable destructuring with strings.
Jacob
# What syntax options exist for variable destructuring/unpacking?
Posted by: username_0 on 2023-05-18
Some languages allow you to write something like
x, y, z = (1, 2, 3)

Which is equivalent to
x = 1
y = 2
z = 3

What are some of the syntax constructs that exist that perform variable destructuring/unpacking?
**Tags:** syntax language-comparison
> **Comments:**
> **username_1**: Generally the syntax for destructuring will mirror the syntax for constructing the same data. So if your language has data structures which can be destructured, then you presumably already have syntax for them.  
---
## 2 answers
### Answer by username_3 on 2023-05-18. Score: 5
For JavaScript, there are two valid syntaxes, depending on what you are destructuring. In both cases they attempt to mirror the data structure they work on:
Array destructuring
Uses [ ] to enclose the variables that need to be unpacked and does so positionally - the first variable takes on the first value, the second variable takes on the second value, etc.:
const someArray = [1, 2, 3];
const [x, y, z] = someArray;

Positions can be skipped via elision - by not supplying a variable:
const someArray = [1, 2, 3];
const [x, , z] = someArray;

Which is essentially the same as:
const x = someArray[0];
const z = someArray[2];

Rest syntax ...
The remainder of the unpacked values can be collected into a single array by using the syntax ..., for example
const someArray = [1, 2, 3];
const [x, ...others] = someArray;

will have others = [2, 3]
Not just for arrays
The common name is "array destructuring" but it does not only work on arrays but any iterable. For example sets or generators:
const someSet = new Set().add(1).add(2).add(3);
const [x, y, z] = someSet;

const someGenerator = function* () {
    yield 1;
    yield 2;
    yield 3;
}
const [x, y, z] = someGenerator();

In a lot of common cases it is more or less the same whether you use it on arrays or not. However, that is not necessarily correct for all iterables - if consuming an iterable keeps producing values, the array destructuring will keep drawing, rather than only get the same position:
const someArray = [1, 2, 3];
const [x] = someArray;
const [y] = someArray;
const [z] = someArray;

Will produce x = 1, y = 1, and z = 1 because each of them is assigned the first position of the array. Destructuring the array produces a new iterator each time that starts from the start.
While
const someGenerator = function* () {
    yield 1;
    yield 2;
    yield 3;
}

const [x] = someGenerator;
const [y] = someGenerator;
const [z] = someGenerator;

Will produce x = 1, y = 2, and z = 3 because there is one iterator in total that keeps producing values.
Object destructuring
Uses { } to enclose the variables that need to be unpacked and does so by name:
const someObject = {x: 1, y: 2, z: 3 };

const { x, y, z } = someObject;

Essentially the same as:
const someObject = {x: 1, y: 2, z: 3 };

const x = someObject.x;
const y = someObject.y;
const z = someObject.z;

The longer form also allows for re-mapping the properties to differently named variables:
const someObject = {x: 1, y: 2, z: 3 };

const { a: x, b: y, c: z } = someObject;

Essentially the same as:
const someObject = {x: 1, y: 2, z: 3 };

const a = someObject.x;
const b = someObject.y;
const c = someObject.z;

Rest syntax ...
Very similar to how the array destructuring syntax can use ... to collect the rest of the unpacked values, the same can be done with object destructuring to collect all key/values that have not been extracted otherwise:
const someObject = {x: 1, y: 2, z: 3 };

const { x, ...others } = someObject;

will have others = { y: 2, z: 3 }
Combining these
These can be arbitrarily nested and combined to access any property and value:
const users = [
    { 
        name: "Fred", 
        userInfo: { likes: "bowling" }, 
        addresses: ["Town of Bedrock", "some previous address"] 
    }
];

const [
    { 
        name, 
        userInfo: { likes: hobby }, 
        addresses: [lastAddress] 
    }
] = user;

Will extract: name = "Fred", hobby = "bowling", and lastAddress = "Town of Bedrock".
> **Comments:**
> **username_4** (2023-05-18): You can also destructure within function parameters `({ name }) => name`, or use iterable destructuring with strings.  
---
### Answer by username_2 on 2023-07-02. Score: 1
An approach I'd like to see would be a construct that combines new automatic-scope object declarations and initializer-like constructs with a compound statement.  Perhaps something like:
union ( int x=foo->bar : 4,8, y = baz->bongo : 3,9;)
{
  ...
}

The syntax would be identifiable by the opening parenthesis following the union keyword--something that would otherwise be impossible.
The "initializers" would need to be lvalues, optionally followed by a bit width and offset.  Such a syntax would invite a compiler to behave as though the declared identifiers were objects of the indicated type which were loaded any time before their value was used, and written back any time after their value was modified, in any manner consistent with normal "caching" semantics (if a compiler modifies the temporary object, future reads would need to come from that object rather than the original until the change was written back; if the compiler reads and caches the original object, but then modifies the orginal object, it would need to ensure that the cached copy was updated or reloaded before it was used againm etc.).
If two or more initializers are bound to the same side-effect-free lvalue expression, a compiler would have to allow for the possibility that changes to one might affect the other, but such allowance would not be required if lvalue expressions have side effects or don't match each other.
Note that while this construct would be semantically most useful when handlings things like bit fields, it could also allow compilers the freedom to keep an object that would be updated multiple times in a register, and consolidate multiple writes to an object, when doing so would be useful, but allow a compiler to flush such cached objectss in cases where the alternative would be an extra register spill (thus allowing what would be the sequence:
load x into r0
... do some stuff with r0
push r0
... do some stuff that needs to use r0 for some other purpose
... pop r0
store r0 into x

to be improved by storing r0 into x before the stuff that would use r0 for some other purpose, and avoiding the need to pop it and then store it.
---
