zeallot
zeallot copied to clipboard
Destructuring Assignment by Name
In Javascript we can do:
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring
I realize that in R, while named list resembles a hash map, it is indeed ordered.
Maybe something like this?
list(a, b) %<-% list(b = 2, a = 1)
# a = 1
# b = 2
Someone else recently posed this to me. I feel the feature is a powerful one and could be added.
I believe the syntax will prove trickiest. I have a couple initial ideas and welcome your thoughts.
c(x: m, y: a) %<-% list(a = "ah", m = "yum")c(x <- m, y <- a) %<-% list(a = "ah", m = "yum")
As much as I love var {p, q} = {p: 1, q: 2}; in JS, I agree it is pretty confusing to differentiate it from positional unpacking.
I like c(x <- m, y <- a) because it confuses me every now and then when I write var {p: foo, q: bar} = o; whether we are assigning values to p, q or foo, bar. It is similar to how rename(data, a = b) always confuses me whether I am renaming a to b, or b now is renamed to a.
More typing though 🤷♂️
The <- is certainly clearer. I also agree the single extra character may be off-putting. I will think over the syntax for a couple days, but I bet I can have a beta version by the end of the weekend (famous last words). Changing the character(s) used is straightforward once the logic is in place. Let me know if you have any further ideas in the meantime.
After a conversation with @pteetor I am actually struggling to come up with a solid use case for this functionality. @saurfang, are there times when this feature is better than using . and ... given that we'll have to complicate the syntax with <-?
Not yet. Funny that I use destructive assignments in Js and Scala day and night but this is not a feature that I miss often when it comes to R. I think mostly because list is not a big part of my R workflow.
I'm still discovering how positional destructive assignment fits in my day to day R flow. I'll let you know if I come across good use case for destructive assignment by name.
This would be a pretty big help for multiple return values from Shiny modules. One of the things we strongly encourage people to do is use named lists to return reactives and other return values from Shiny module server functions. In these cases, the returned list usually has little inherent meaning; it's the elements of the list that you want to turn into variables.
Having destructuring assignment by name would make the coupling between caller and callee robust to reordering of the named lists returned by the modules.
I haven't thought much about the syntax but semantically I'm really looking for the equivalent of e.g.
let {a, b} = {a: 10, b: 20, c: 30, d: 40};
FWIW, this is the idiom I've been using to do this:
list2env(my_list[c('a', 'b', 'c')])
c(a=, b=) %<-% list(b = 2, a = 1)
:heart_eyes:
Allow optional renaming by providing a value?
c(foo=a, b=) %<-% list(b = 2, a = 1)
That's an interesting approach I hadn't yet considered.
I was working on an idea borrowed from javascript, c(a: b, b: a) %<-% list(b = 2, a = 1). I wasn't particularly enthused with this syntax because : has a very different meaning for R users.
Right now = specifies a default value. If the default is a name I think it's reasonable to first check the RHS and then check the calling environment for the specified object. The var= syntax is more than : intuitive for R users. I'll give it a go. Thanks for the suggestion!