Destructuring
Destructuring is syntax sugar that allows splitting of a value of a
conjunction (product) type like point(x, y i32)
into two
variabes a
, b
holding the two components of the
conjunction value.
Destructuring in other languages
Haskell
Haskell's where
statement can be used to destructure as follows:
first tuple = x
where
(x, y) = tuple
Java
Several JDK Enhancement Proposals have recently added destructuring to Java (JEP405, JEP406, JEP420, JEP427, JEP432, JEP433, JEP440, JEP441). Here are examples using from JEP440:
In a switch
case:
// As of Java 21
record MyPair(S fst, T snd){};
static void recordInference(MyPair pair){
switch (pair) {
case MyPair(var f, var s) ->
... // Inferred record pattern MyPair(var f, var s)
...
}
}
In an instanceof
expression:
// As of Java 21
record Box(T t) {}
static void test1(Box> bbs) {
if (bbs instanceof Box>(Box(var s))) {
System.out.println("String " + s);
}
}
In an instanceof
expression, type parameters can be inferred:
// As of Java 21
static void test2(Box> bbs) {
if (bbs instanceof Box(Box(var s))) {
System.out.println("String " + s);
}
}
Rust
Here is an example for a triple taken from the Rust documentation:
fn main() {
let triple = (0, -2, 3);
// TODO ^ Try different values for `triple`
println!("Tell me about {:?}", triple);
// Match can be used to destructure a tuple
match triple {
// Destructure the second and third elements
(0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
(1, ..) => println!("First is `1` and the rest doesn't matter"),
(.., 2) => println!("last is `2` and the rest doesn't matter"),
(3, .., 4) => println!("First is `3`, last is `4`, and the rest doesn't matter"),
// `..` can be used to ignore the rest of the tuple
_ => println!("It doesn't matter what they are"),
// `_` means don't bind the value to a variable
}
}
And for a struct from the Rust documentation:
fn main() {
struct Foo {
x: (u32, u32),
y: u32,
}
// Try changing the values in the struct to see what happens
let foo = Foo { x: (1, 2), y: 3 };
match foo {
Foo { x: (1, b), y } => println!("First of x is 1, b = {}, y = {} ", b, y),
// you can destructure structs and rename the variables,
// the order is not important
Foo { y: 2, x: i } => println!("y is 2, i = {:?}", i),
// and you can also ignore some variables:
Foo { y, .. } => println!("y = {}, we don't care about x", y),
// this will give an error: pattern does not mention field `x`
//Foo { y } => println!("y = {}", y),
}
}
Syntax alternatives for Fuzion
Destructuring is useful in different contexts, e.g.
- Assignments
p := point x1 y1 px, py := p
- Loop index variable assignment
ps Set point := ... for p in points px, py := p do say "$px,$py"
- Loop iterator variable assignment
ps Set point := ... for px, py in points do say "$px,$py"
- lambdas
filter_points(pred point -> bool) is ... filter_points (x,y -> x*x+y*y <= 100)
- matches with explicit type
x option point := ... match x point px py -> say "$px $px" nil -> say "no point"
- matches without explicit type
x option point := ... match x px, py -> say "$px $px" nil -> say "no point"
Problems to be solved
- syntax should best be the same for all these uses
- we need syntax for destructuring without explicit type
px, py
- we need syntax for destructuring with explicit type
point px py