Programming Languages - Destructuring (Unpacking)

Destructuring (also known as unpacking or pattern matching decomposition) is a syntax feature that extracts values from arrays, objects, tuples, or structs directly into distinct individual variables.

JavaScript / TypeScript

JavaScript provides extensive destructuring capabilities for arrays, objects, and function parameters.

Array Destructuring

const numbers = [10, 20, 30, 40, 50];

// Basic, skipping elements, and rest syntax
const [first, second] = numbers;            // first = 10, second = 20
const [, , third, ...rest] = numbers;       // third = 30, rest = [40, 50]

// Default values
const [a = 1, b = 2] = [99];                // a = 99, b = 2

// Variable swapping without temp variable
let x = 1, y = 2;
[x, y] = [y, x];

Object Destructuring

const user = { id: 101, username: 'alice', profile: { age: 30 } };

// Basic extraction, renaming, and default values
const { username } = user;
const { id: userId, role = 'member' } = user; // Renamed to userId, role defaults to 'member'

// Nested object destructuring
const { profile: { age } } = user;

// Parameter destructuring in functions
function renderUser({ id, username }) {
  console.log(`${id}: ${username}`);
}

Python

Python refers to destructuring as sequence unpacking and extended iterable unpacking.

Tuple & List Unpacking

coords = (40.7128, -74.0060)
lat, lon = coords

# Extended iterable unpacking with the star (*) operator
numbers = [1, 2, 3, 4, 5]
first, *middle, last = numbers  # first = 1, middle = [2, 3, 4], last = 5
head, *tail = numbers           # head = 1, tail = [2, 3, 4, 5]

# Variable swap
a, b = b, a

Structural Pattern Matching (Python 3.10+)

point = (0, 5)

match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y-axis at {y}")
    case (x, 0):
        print(f"X-axis at {x}")
    case (x, y):
        print(f"Point at ({x}, {y})")

Rust

Rust deeply integrates destructuring with its pattern matching system (let, match, and if let).

Tuples and Structs

struct Point { x: i32, y: i32, z: i32 }

fn main() {
    // Tuple unpacking
    let (a, b, c) = (1, "hello", 3.14);

    // Struct destructuring & field renaming
    let p = Point { x: 10, y: 20, z: 30 };
    let Point { x, y: y_coord, .. } = p; // Ignores z with '..'

    // Matching enums & destructuring payloads
    let msg = Some(42);
    if let Some(val) = msg {
        println!("Inner value: {}", val);
    }
}

C++ (C++17 Structured Bindings)

C++17 introduced structured bindings for arrays, tuples, and aggregates:

#include <tuple>
#include <string>

struct User {
    int id;
    std::string name;
};

int main() {
    // Tuple destructuring
    auto [code, message] = std::make_tuple(404, "Not Found");

    // Struct / Aggregate destructuring
    User u{1, "Alice"};
    auto [id, name] = u;

    // Destructuring with references (avoids copies)
    const auto& [refId, refName] = u;
}

Go (Multiple Return Value Assignment)

While Go does not have generic pattern matching or object destructuring, it supports multiple return values and blank identifier (_) assignment:

// Map lookup with 'comma-ok' idiom
val, ok := cache[key]

// Function multiple return values
result, err := fetchData()
if err != nil {
    return err
}

// Discarding unwanted values
_, exists := set[key]

Summary Comparison

Language Array / Tuple Object / Struct Rest / Collect Default Values Pattern Matching
JavaScript [a, b] = arr {a, b} = obj ...rest {a = 1} TC39 (Proposal)
Python a, b = tup N/A (Dict keys) *rest Via dict.get match / case
Rust (a, b) = tup Point {x, y} .. N/A match, if let
C++17 auto [a, b] auto [x, y] N/A N/A C++26 (Planned)
Go Multiple return N/A N/A N/A type switch