Wednesday 7 February 2018

Destructuring/Deconstructing

Destructured assignment (simplify how to return multiple values from a function and assign them to the corresponding variables) is a feature that I had really missed in both C# and Javascript, and it has been added almost at the same time, with a different name and with different behaviour. I'll write a small summary here.

In C# the feature is called Deconstruction and you can use it out of the box returning the new ValueTuple type from your methods. ValueTuple has builtin support for deconstruction. For other types, in order to allow deconstruction the class will have to provide Deconstruct method/s. In both cases, there's a single syntax for the assignment "()". So the thing is like:

static (string name, string city, int age) GetData()
{
 return ("Didier", "Toulouse", 45);
}

var (name, city, age) = GetData();
//as the returned tuple has names I can switch the order
(city, name, age) = GetData();

// Compilation Error: Cannot deconstruct a tuple of '3' elements into '2' variables
// (name, age) = GetData();

//so we have to use a discard
(name, _, age) = GetData();

//we can use different names
var (n, c, a) = GetData();

As you can see in the example if you want to assign less variables than the elements in the returned tuple you can use "_" (called discards). Discards make much sense when the variable names you use and those in the returned tuple do not match, or when the returned tuples is not using names, but in the example above, I don't see the reason for getting that Compilation Error and needing the discards, but well, I guess I'm missing something.

In Javascript the feature is called destructuring and we have 2 different syntaxes, "{}" for object destructuring and "[]" for array destructuring. Some basic example:

function getAddress(){
 return {name: "Marseille", population: 1600000};
}

let {name, population} = getAddress();

//-------------------------

function getCities(){
 return ["Paris", "Toulouse", "Marseille"];
}

let [capital, aero, mediterranean] = getCities();

I think there's not much to say about Object destructuring, but for Array destructuring the main thing to bear in mind is that it can be used for any iterable object, not just for arrays (so probably it would be more clear to call it "destructuring with array syntax"). This means that if we want to implement destructuring in one custom object, same as in C# we use Deconstruct methods, in javascript we'll use the iterable protocol. Let's see an example of how the same object is destructured differently with the object and array syntaxes.

let obj = {
 name: "Francois",
 city: "Marseille"
};

obj[Symbol.iterator] = function* () {
 yield "item1";
 yield "item2";
 yield "item3";
};

//object destructuring, can not be customised 
let {name, city} = obj;
console.log("name: " + name + " city: " + city); 

console.log("----------------");

let [a, b] = obj;
console.log("a: " + a + " b: " + b); //a: item1 b: item2


//we can use "discards" ( ,)if we want access to only certain elements (with "holes" in between)
[a, , b] = obj;
console.log("a: " + a + " b: " + b); //a: item1 b: item3

As shown above, discards in javascript use the " ," syntax rather than "_". One interesting feature present in javascript and missing in C# (as far as I know)is destructuring into function parameters.


function printAddress({street, number, city}) {
 console.log(street + ", " + number + " (" + city + ")" );
}

let address = {
 street: "Republique", 
 number: 45,
 city: "Paris"
};

printAddress(address);

No comments:

Post a Comment