On Sat, 11 Mar 2023 11:11:06 -0500 Duncan Murdoch <murdoch.duncan at gmail.com> wrote:> That's clear, but your proposal violates a very basic property of the > language, i.e. that all statements are expressions and have a value.How about reframing this feature request from multiple assignment (which does go contrary to "everything has only one value, even if it's sometimes invisible(NULL)") to "structured binding" / "destructuring assignment" [*], which takes this single single value returned by the expression and subsets it subject to certain rules? It may be easier to make a decision on the semantics for destructuring assignment (e.g. languages which have this feature typically allow throwing unneeded parts of the return value away), and it doesn't seem to break as much of the rest of the language if implemented. I see you've already mentioned it ("JavaScript-like"). I think it would fulfil Sebastian's requirements too, as long as it is considered "true assignment" by the rest of the language. The hard part is to propose the actual grammar of the new feature (in terms of src/main/gram.y, preferably without introducing conflicts) and its semantics (including the corner cases, some of which you have already mentioned). I'm not sure I'm up to the task. -- Best regards, Ivan [*] https://en.cppreference.com/w/cpp/language/structured_binding https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Duncan Murdoch
2023-Mar-11 18:38 UTC
[Rd] Multiple Assignment built into the R Interpreter?
On 11/03/2023 11:57 a.m., Ivan Krylov wrote:> On Sat, 11 Mar 2023 11:11:06 -0500 > Duncan Murdoch <murdoch.duncan at gmail.com> wrote: > >> That's clear, but your proposal violates a very basic property of the >> language, i.e. that all statements are expressions and have a value. > > How about reframing this feature request from multiple assignment > (which does go contrary to "everything has only one value, even if it's > sometimes invisible(NULL)") to "structured binding" / "destructuring > assignment" [*], which takes this single single value returned by the > expression and subsets it subject to certain rules? It may be easier to > make a decision on the semantics for destructuring assignment (e.g. > languages which have this feature typically allow throwing unneeded > parts of the return value away), and it doesn't seem to break as much > of the rest of the language if implemented. > > I see you've already mentioned it ("JavaScript-like"). I think it would > fulfil Sebastian's requirements too, as long as it is considered "true > assignment" by the rest of the language. > > The hard part is to propose the actual grammar of the new feature (in > terms of src/main/gram.y, preferably without introducing conflicts) and > its semantics (including the corner cases, some of which you have > already mentioned). I'm not sure I'm up to the task. >If I were doing it, here's what I'd propose: '[' formlist ']' LEFT_ASSIGN expr '[' formlist ']' EQ_ASSIGN expr expr RIGHT_ASSIGN '[' formlist ']' where `formlist` has the syntax of the formals list for a function definition. This would have the following semantics: { *tmp* <- expr # For arguments with no "default" expression, argname1 <- *tmp*[[1]] argname2 <- *tmp*[[2]] ... # For arguments with a default listed argname3 <- with(*tmp*, default3) } The value of the whole thing would therefore be (invisibly) the value of the last item in the assignment. Two examples: [A, B, C] <- expr # assign the first three elements of expr to A, B, and C [A, B, C = a + b] <- expr # assign the first two elements of expr # to A and B, # assign with(expr, a + b) to C. Unfortunately, I don't think this could be done entirely by transforming the expression (which is the way |> was done), and that makes it a lot harder to write and to reason about. E.g. what does this do? A <- 0 [A, B = A + 10] <- list(1, A = 2) According to the recipe above, I think it sets A to 1 and B to 12, but maybe a user would expect B to be 10 or 11. And according to that recipe this is an error: [A, B = A + 10] <- c(1, A = 2) which probably isn't what a user would expect, given that this is fine: [A, B] <- c(1, 2) Duncan Murdoch