I wonder if the real confusino is not R's scope rules? (begin .) is not Lisp, it's Scheme (a major Lisp dialect), and in Scheme, (begin (define x ...) (define y ...) ...) declares variables x and y that are local to the (begin ...) form, just like Algol 68. That's weirdness 1. Javascript had a similar weirdness, when the ECMAscript process eventually addressed. But the real weirdness in R is not just that the existence of variables is indifferent to the presence of curly braces, it's that it's *dynamic*. In f <- function (...) { ... use x ... x <- ... ... use x ... } the two occurrences of "use x" refer to DIFFERENT variables. The first occurrence refers to the x that exists outside the function. It has to: the local variable does not exist yet. The assignment *creates* the variable, so the second occurrence of "use x" refers to the inner variable. Here's an actual example.> x <- 137 > f <- function () {+ a <- x + x <- 42 + b <- x + list(a=a, b=b) + }> f()$a [1] 137 $b [1] 42 Many years ago I set out to write a compiler for R, and this was the issue that finally sank my attempt. It's not whether the occurrence of "use x" is *lexically* before the creation of x. It's when the assignment is *executed* that makes the difference. Different paths of execution through a function may result in it arriving at its return point with different sets of local variables. R is the only language I routinely use that does this. So rule 1: whether an identifier in an R function refers to an outer variable or a local variable depends on whether an assignment creating that local variable has been executed yet. And rule 2: the scope of a local variable is the whole function. If the following transcript not only makes sense to you, but is exactly what you expect, congratulations, you understand local variables in R.> x <- 0 > g <- function () {+ n <- 10 + r <- numeric(n) + for (i in 1:n) { + if (i == 6) x <- 100 + r[i] <- x + i + } + r + }> g()[1] 1 2 3 4 5 106 107 108 109 110 On Fri, 13 Jan 2023 at 23:28, Valentin Petzel <valentin at petzel.at> wrote:> Hello Akshay, > > R is quite inspired by LISP, where this is a common thing. It is not in > fact that {...} returned something, rather any expression evalulates to > some value, and for a compound statement that is the last evaluated > expression. > > {...} might be seen as similar to LISPs (begin ...). > > Now this is a very different thing compared to {...} in something like C, > even if it looks or behaves similarly. But in R {...} is in fact an > expression and thus has evaluate to some value. This also comes with some > nice benefits. > > You do not need to use {...} for anything that is a single statement. But > you can in each possible place use {...} to turn multiple statements into > one. > > Now think about a statement like this > > f <- function(n) { > x <- runif(n) > x**2 > } > > Then we can do > > y <- f(10) > > Now, you suggested way would look like this: > > f <- function(n) { > x <- runif(n) > y <- x**2 > } > > And we'd need to do something like: > > f(10) > y <- somehow_get_last_env_of_f$y > > So having a compound statement evaluate to a value clearly has a benefit. > > Best Regards, > Valentin > > 09.01.2023 18:05:58 akshay kulkarni <akshay_e4 at hotmail.com>: > > > Dear Valentin, > > But why should {....} "return" a value? It > could just as well evaluate all the expressions and store the resulting > objects in whatever environment the interpreter chooses, and then it would > be left to the user to manipulate any object he chooses. Don't you think > returning the last, or any value, is redundant? We are living in the > 21st century world, and the R-core team might,I suppose, have a definite > reason for"returning" the last value. Any comments? > > > > Thanking you, > > Yours sincerely, > > AKSHAY M KULKARNI > > > > ---------------------------------------- > > *From:* Valentin Petzel <valentin at petzel.at> > > *Sent:* Monday, January 9, 2023 9:18 PM > > *To:* akshay kulkarni <akshay_e4 at hotmail.com> > > *Cc:* R help Mailing list <r-help at r-project.org> > > *Subject:* Re: [R] return value of {....} > > > > Hello Akshai, > > > > I think you are confusing {...} with local({...}). This one will > evaluate the expression in a separate environment, returning the last > expression. > > > > {...} simply evaluates multiple expressions as one and returns the > result of the last line, but it still evaluates each expression. > > > > Assignment returns the assigned value, so we can chain assignments like > this > > > > a <- 1 + (b <- 2) > > > > conveniently. > > > > So when is {...} useful? Well, anyplace where you want to execute > complex stuff in a function argument. E.g. you might do: > > > > data %>% group_by(x) %>% summarise(y = {if(x[1] > 10) sum(y) else > mean(y)}) > > > > Regards, > > Valentin Petzel > > > > 09.01.2023 15:47:53 akshay kulkarni <akshay_e4 at hotmail.com>: > > > >> Dear members, > >> I have the following code: > >> > >>> TB <- {x <- 3;y <- 5} > >>> TB > >> [1] 5 > >> > >> It is consistent with the documentation: For {, the result of the last > expression evaluated. This has the visibility of the last evaluation. > >> > >> But both x AND y are created, but the "return value" is y. How can this > be advantageous for solving practical problems? Specifically, consider the > following code: > >> > >> F <- function(X) { expr; expr2; { expr5; expr7}; expr8;expr10} > >> > >> Both expr5 and expr7 are created, and are accessible by the code > outside of the nested braces right? But the "return value" of the nested > braces is expr7. So doesn't this mean that only expr7 should be accessible? > Please help me entangle this (of course the return value of F is expr10, > and all the other objects created by the preceding expressions are deleted. > But expr5 is not, after the control passes outside of the nested braces!) > >> > >> Thanking you, > >> Yours sincerely, > >> AKSHAY M KULKARNI > >> > >> [[alternative HTML version deleted]] > >> > >> ______________________________________________ > >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > >> https://stat.ethz.ch/mailman/listinfo/r-help > >> PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > >> and provide commented, minimal, self-contained, reproducible code. > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]]
Richard, A slight addition to your code shows an important aspect of R, local vs. global variables: x <- 137 f <- function () { a <- x x <- 42 b <- x list(a=a, b=b) } f() print(x) ________________________________________ From: R-help <r-help-bounces at r-project.org> on behalf of Richard O'Keefe <raoknz at gmail.com> Sent: Sunday, January 15, 2023 6:39 PM To: Valentin Petzel Cc: R help Mailing list Subject: Re: [R] return value of {....} I wonder if the real confusino is not R's scope rules? (begin .) is not Lisp, it's Scheme (a major Lisp dialect), and in Scheme, (begin (define x ...) (define y ...) ...) declares variables x and y that are local to the (begin ...) form, just like Algol 68. That's weirdness 1. Javascript had a similar weirdness, when the ECMAscript process eventually addressed. But the real weirdness in R is not just that the existence of variables is indifferent to the presence of curly braces, it's that it's *dynamic*. In f <- function (...) { ... use x ... x <- ... ... use x ... } the two occurrences of "use x" refer to DIFFERENT variables. The first occurrence refers to the x that exists outside the function. It has to: the local variable does not exist yet. The assignment *creates* the variable, so the second occurrence of "use x" refers to the inner variable. Here's an actual example.> x <- 137 > f <- function () {+ a <- x + x <- 42 + b <- x + list(a=a, b=b) + }> f()$a [1] 137 $b [1] 42 Many years ago I set out to write a compiler for R, and this was the issue that finally sank my attempt. It's not whether the occurrence of "use x" is *lexically* before the creation of x. It's when the assignment is *executed* that makes the difference. Different paths of execution through a function may result in it arriving at its return point with different sets of local variables. R is the only language I routinely use that does this. So rule 1: whether an identifier in an R function refers to an outer variable or a local variable depends on whether an assignment creating that local variable has been executed yet. And rule 2: the scope of a local variable is the whole function. If the following transcript not only makes sense to you, but is exactly what you expect, congratulations, you understand local variables in R.> x <- 0 > g <- function () {+ n <- 10 + r <- numeric(n) + for (i in 1:n) { + if (i == 6) x <- 100 + r[i] <- x + i + } + r + }> g()[1] 1 2 3 4 5 106 107 108 109 110 On Fri, 13 Jan 2023 at 23:28, Valentin Petzel <valentin at petzel.at> wrote:> Hello Akshay, > > R is quite inspired by LISP, where this is a common thing. It is not in > fact that {...} returned something, rather any expression evalulates to > some value, and for a compound statement that is the last evaluated > expression. > > {...} might be seen as similar to LISPs (begin ...). > > Now this is a very different thing compared to {...} in something like C, > even if it looks or behaves similarly. But in R {...} is in fact an > expression and thus has evaluate to some value. This also comes with some > nice benefits. > > You do not need to use {...} for anything that is a single statement. But > you can in each possible place use {...} to turn multiple statements into > one. > > Now think about a statement like this > > f <- function(n) { > x <- runif(n) > x**2 > } > > Then we can do > > y <- f(10) > > Now, you suggested way would look like this: > > f <- function(n) { > x <- runif(n) > y <- x**2 > } > > And we'd need to do something like: > > f(10) > y <- somehow_get_last_env_of_f$y > > So having a compound statement evaluate to a value clearly has a benefit. > > Best Regards, > Valentin > > 09.01.2023 18:05:58 akshay kulkarni <akshay_e4 at hotmail.com>: > > > Dear Valentin, > > But why should {....} "return" a value? It > could just as well evaluate all the expressions and store the resulting > objects in whatever environment the interpreter chooses, and then it would > be left to the user to manipulate any object he chooses. Don't you think > returning the last, or any value, is redundant? We are living in the > 21st century world, and the R-core team might,I suppose, have a definite > reason for"returning" the last value. Any comments? > > > > Thanking you, > > Yours sincerely, > > AKSHAY M KULKARNI > > > > ---------------------------------------- > > *From:* Valentin Petzel <valentin at petzel.at> > > *Sent:* Monday, January 9, 2023 9:18 PM > > *To:* akshay kulkarni <akshay_e4 at hotmail.com> > > *Cc:* R help Mailing list <r-help at r-project.org> > > *Subject:* Re: [R] return value of {....} > > > > Hello Akshai, > > > > I think you are confusing {...} with local({...}). This one will > evaluate the expression in a separate environment, returning the last > expression. > > > > {...} simply evaluates multiple expressions as one and returns the > result of the last line, but it still evaluates each expression. > > > > Assignment returns the assigned value, so we can chain assignments like > this > > > > a <- 1 + (b <- 2) > > > > conveniently. > > > > So when is {...} useful? Well, anyplace where you want to execute > complex stuff in a function argument. E.g. you might do: > > > > data %>% group_by(x) %>% summarise(y = {if(x[1] > 10) sum(y) else > mean(y)}) > > > > Regards, > > Valentin Petzel > > > > 09.01.2023 15:47:53 akshay kulkarni <akshay_e4 at hotmail.com>: > > > >> Dear members, > >> I have the following code: > >> > >>> TB <- {x <- 3;y <- 5} > >>> TB > >> [1] 5 > >> > >> It is consistent with the documentation: For {, the result of the last > expression evaluated. This has the visibility of the last evaluation. > >> > >> But both x AND y are created, but the "return value" is y. How can this > be advantageous for solving practical problems? Specifically, consider the > following code: > >> > >> F <- function(X) { expr; expr2; { expr5; expr7}; expr8;expr10} > >> > >> Both expr5 and expr7 are created, and are accessible by the code > outside of the nested braces right? But the "return value" of the nested > braces is expr7. So doesn't this mean that only expr7 should be accessible? > Please help me entangle this (of course the return value of F is expr10, > and all the other objects created by the preceding expressions are deleted. > But expr5 is not, after the control passes outside of the nested braces!) > >> > >> Thanking you, > >> Yours sincerely, > >> AKSHAY M KULKARNI > >> > >> [[alternative HTML version deleted]] > >> > >> ______________________________________________ > >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > >> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstat.ethz.ch%2Fmailman%2Flistinfo%2Fr-help&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=DYZ1Jle5re1jwM%2F1pVrpS%2BwOeT%2BgjNXQZz0Fq8N4sIU%3D&reserved=0 > >> PLEASE do read the posting guide > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.r-project.org%2Fposting-guide.html&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=q1Gy%2FTQd0eXsa8fUKW3slt%2Byn7EUfqmOOqPGDoxYx4U%3D&reserved=0 > >> and provide commented, minimal, self-contained, reproducible code. > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstat.ethz.ch%2Fmailman%2Flistinfo%2Fr-help&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=DYZ1Jle5re1jwM%2F1pVrpS%2BwOeT%2BgjNXQZz0Fq8N4sIU%3D&reserved=0 > PLEASE do read the posting guide > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.r-project.org%2Fposting-guide.html&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=q1Gy%2FTQd0eXsa8fUKW3slt%2Byn7EUfqmOOqPGDoxYx4U%3D&reserved=0 > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]] ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstat.ethz.ch%2Fmailman%2Flistinfo%2Fr-help&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=DYZ1Jle5re1jwM%2F1pVrpS%2BwOeT%2BgjNXQZz0Fq8N4sIU%3D&reserved=0 PLEASE do read the posting guide https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.r-project.org%2Fposting-guide.html&data=05%7C01%7CJSorkin%40som.umaryland.edu%7C7667e3a25e004319a09408daf751c352%7C717009a620de461a88940312a395cac9%7C0%7C0%7C638094227808126030%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=q1Gy%2FTQd0eXsa8fUKW3slt%2Byn7EUfqmOOqPGDoxYx4U%3D&reserved=0 and provide commented, minimal, self-contained, reproducible code.
Well, weirdness is in the eyes of the beholder, I think. In any case, R's scoping procedures are described in ?environment and ?assign and ?function, among other places; and in detail in the R Language Definition. So no matter the behavior, as long as it is clearly documented -- and consistent of course -- it's OK by me: it's my job to learn it. Perhaps this just reflects my ignorance of what might be considered "better" alternatives. And of course, someone *did* write a compiler for R. Cheers, Bert On Sun, Jan 15, 2023 at 3:39 PM Richard O'Keefe <raoknz at gmail.com> wrote:> > I wonder if the real confusino is not R's scope rules? > (begin .) is not Lisp, it's Scheme (a major Lisp dialect), > and in Scheme, (begin (define x ...) (define y ...) ...) > declares variables x and y that are local to the (begin ...) > form, just like Algol 68. That's weirdness 1. Javascript > had a similar weirdness, when the ECMAscript process eventually > addressed. But the real weirdness in R is not just that the > existence of variables is indifferent to the presence of curly > braces, it's that it's *dynamic*. In > f <- function (...) { > ... use x ... > x <- ... > ... use x ... > } > the two occurrences of "use x" refer to DIFFERENT variables. > The first occurrence refers to the x that exists outside the > function. It has to: the local variable does not exist yet. > The assignment *creates* the variable, so the second > occurrence of "use x" refers to the inner variable. > Here's an actual example. > > x <- 137 > > f <- function () { > + a <- x > + x <- 42 > + b <- x > + list(a=a, b=b) > + } > > f() > $a > [1] 137 > $b > [1] 42 > > Many years ago I set out to write a compiler for R, and this was > the issue that finally sank my attempt. It's not whether the > occurrence of "use x" is *lexically* before the creation of x. > It's when the assignment is *executed* that makes the difference. > Different paths of execution through a function may result in it > arriving at its return point with different sets of local variables. > R is the only language I routinely use that does this. > > So rule 1: whether an identifier in an R function refers to an > outer variable or a local variable depends on whether an assignment > creating that local variable has been executed yet. > And rule 2: the scope of a local variable is the whole function. > > If the following transcript not only makes sense to you, but is > exactly what you expect, congratulations, you understand local > variables in R. > > > x <- 0 > > g <- function () { > + n <- 10 > + r <- numeric(n) > + for (i in 1:n) { > + if (i == 6) x <- 100 > + r[i] <- x + i > + } > + r > + } > > g() > [1] 1 2 3 4 5 106 107 108 109 110 > > > On Fri, 13 Jan 2023 at 23:28, Valentin Petzel <valentin at petzel.at> wrote: > > > Hello Akshay, > > > > R is quite inspired by LISP, where this is a common thing. It is not in > > fact that {...} returned something, rather any expression evalulates to > > some value, and for a compound statement that is the last evaluated > > expression. > > > > {...} might be seen as similar to LISPs (begin ...). > > > > Now this is a very different thing compared to {...} in something like C, > > even if it looks or behaves similarly. But in R {...} is in fact an > > expression and thus has evaluate to some value. This also comes with some > > nice benefits. > > > > You do not need to use {...} for anything that is a single statement. But > > you can in each possible place use {...} to turn multiple statements into > > one. > > > > Now think about a statement like this > > > > f <- function(n) { > > x <- runif(n) > > x**2 > > } > > > > Then we can do > > > > y <- f(10) > > > > Now, you suggested way would look like this: > > > > f <- function(n) { > > x <- runif(n) > > y <- x**2 > > } > > > > And we'd need to do something like: > > > > f(10) > > y <- somehow_get_last_env_of_f$y > > > > So having a compound statement evaluate to a value clearly has a benefit. > > > > Best Regards, > > Valentin > > > > 09.01.2023 18:05:58 akshay kulkarni <akshay_e4 at hotmail.com>: > > > > > Dear Valentin, > > > But why should {....} "return" a value? It > > could just as well evaluate all the expressions and store the resulting > > objects in whatever environment the interpreter chooses, and then it would > > be left to the user to manipulate any object he chooses. Don't you think > > returning the last, or any value, is redundant? We are living in the > > 21st century world, and the R-core team might,I suppose, have a definite > > reason for"returning" the last value. Any comments? > > > > > > Thanking you, > > > Yours sincerely, > > > AKSHAY M KULKARNI > > > > > > ---------------------------------------- > > > *From:* Valentin Petzel <valentin at petzel.at> > > > *Sent:* Monday, January 9, 2023 9:18 PM > > > *To:* akshay kulkarni <akshay_e4 at hotmail.com> > > > *Cc:* R help Mailing list <r-help at r-project.org> > > > *Subject:* Re: [R] return value of {....} > > > > > > Hello Akshai, > > > > > > I think you are confusing {...} with local({...}). This one will > > evaluate the expression in a separate environment, returning the last > > expression. > > > > > > {...} simply evaluates multiple expressions as one and returns the > > result of the last line, but it still evaluates each expression. > > > > > > Assignment returns the assigned value, so we can chain assignments like > > this > > > > > > a <- 1 + (b <- 2) > > > > > > conveniently. > > > > > > So when is {...} useful? Well, anyplace where you want to execute > > complex stuff in a function argument. E.g. you might do: > > > > > > data %>% group_by(x) %>% summarise(y = {if(x[1] > 10) sum(y) else > > mean(y)}) > > > > > > Regards, > > > Valentin Petzel > > > > > > 09.01.2023 15:47:53 akshay kulkarni <akshay_e4 at hotmail.com>: > > > > > >> Dear members, > > >> I have the following code: > > >> > > >>> TB <- {x <- 3;y <- 5} > > >>> TB > > >> [1] 5 > > >> > > >> It is consistent with the documentation: For {, the result of the last > > expression evaluated. This has the visibility of the last evaluation. > > >> > > >> But both x AND y are created, but the "return value" is y. How can this > > be advantageous for solving practical problems? Specifically, consider the > > following code: > > >> > > >> F <- function(X) { expr; expr2; { expr5; expr7}; expr8;expr10} > > >> > > >> Both expr5 and expr7 are created, and are accessible by the code > > outside of the nested braces right? But the "return value" of the nested > > braces is expr7. So doesn't this mean that only expr7 should be accessible? > > Please help me entangle this (of course the return value of F is expr10, > > and all the other objects created by the preceding expressions are deleted. > > But expr5 is not, after the control passes outside of the nested braces!) > > >> > > >> Thanking you, > > >> Yours sincerely, > > >> AKSHAY M KULKARNI > > >> > > >> [[alternative HTML version deleted]] > > >> > > >> ______________________________________________ > > >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > > >> https://stat.ethz.ch/mailman/listinfo/r-help > > >> PLEASE do read the posting guide > > http://www.R-project.org/posting-guide.html > > >> and provide commented, minimal, self-contained, reproducible code. > > > > [[alternative HTML version deleted]] > > > > ______________________________________________ > > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > > https://stat.ethz.ch/mailman/listinfo/r-help > > PLEASE do read the posting guide > > http://www.R-project.org/posting-guide.html > > and provide commented, minimal, self-contained, reproducible code. > > > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.
Richard, I appreciate your observations. As regularly noted, there are many possible forks in the road to designing a language and it seems someone is determined to try every possible fork. Yes, some languages that are compiled, or like JavaScript, read the entire function before executing it and promote some parts written further down to the top so all variable declarations, as one example, are done before executing any remaining code. If you look at R, if you decide to use a library, you can ask for it near the top or just before you want to use it. I think they get executed as needed so if you only load it in one branch of an IF statement, ... We can debate good and bad subjective choices in language design BUT for practical purposes, what matters is that a feature IS a certain way and you use it consistently with what is documented, not what you wish it was like. R has an interpreter that arguably may be simple and keep reading small sections of code and executing them and then getting more. Much of the code is not even evaluated till much later or never and thus it may not be trivial to do any kind of look-ahead and adjustment. Many languages now look a bit silly after some changes are made or things added that make the earlier way look clumsy. Some features may even be deprecated and eventually removed, or the language forks again and people argue that everyone should upgrade to the new version 12.x and so on. Do note R lets you use rm(x) and also supports multiple environments including new dynamic ones so your example might have a region where an x is used in quite a few ways such as asking some function call to be evaluated in a specific environment. This flexibility would be harder if you asked the interpreter to do things like some other languages that may not support much. However, lots of languages with scoping rules will indeed allow you to use variables in outer scopes or hidden scopes and so on. To each their own. -----Original Message----- From: R-help <r-help-bounces at r-project.org> On Behalf Of Richard O'Keefe Sent: Sunday, January 15, 2023 6:39 PM To: Valentin Petzel <valentin at petzel.at> Cc: R help Mailing list <r-help at r-project.org> Subject: Re: [R] return value of {....} I wonder if the real confusino is not R's scope rules? (begin .) is not Lisp, it's Scheme (a major Lisp dialect), and in Scheme, (begin (define x ...) (define y ...) ...) declares variables x and y that are local to the (begin ...) form, just like Algol 68. That's weirdness 1. Javascript had a similar weirdness, when the ECMAscript process eventually addressed. But the real weirdness in R is not just that the existence of variables is indifferent to the presence of curly braces, it's that it's *dynamic*. In f <- function (...) { ... use x ... x <- ... ... use x ... } the two occurrences of "use x" refer to DIFFERENT variables. The first occurrence refers to the x that exists outside the function. It has to: the local variable does not exist yet. The assignment *creates* the variable, so the second occurrence of "use x" refers to the inner variable. Here's an actual example.> x <- 137 > f <- function () {+ a <- x + x <- 42 + b <- x + list(a=a, b=b) + }> f()$a [1] 137 $b [1] 42 Many years ago I set out to write a compiler for R, and this was the issue that finally sank my attempt. It's not whether the occurrence of "use x" is *lexically* before the creation of x. It's when the assignment is *executed* that makes the difference. Different paths of execution through a function may result in it arriving at its return point with different sets of local variables. R is the only language I routinely use that does this. So rule 1: whether an identifier in an R function refers to an outer variable or a local variable depends on whether an assignment creating that local variable has been executed yet. And rule 2: the scope of a local variable is the whole function. If the following transcript not only makes sense to you, but is exactly what you expect, congratulations, you understand local variables in R.> x <- 0 > g <- function () {+ n <- 10 + r <- numeric(n) + for (i in 1:n) { + if (i == 6) x <- 100 + r[i] <- x + i + } + r + }> g()[1] 1 2 3 4 5 106 107 108 109 110 On Fri, 13 Jan 2023 at 23:28, Valentin Petzel <valentin at petzel.at> wrote:> Hello Akshay, > > R is quite inspired by LISP, where this is a common thing. It is not > in fact that {...} returned something, rather any expression > evalulates to some value, and for a compound statement that is the > last evaluated expression. > > {...} might be seen as similar to LISPs (begin ...). > > Now this is a very different thing compared to {...} in something like > C, even if it looks or behaves similarly. But in R {...} is in fact an > expression and thus has evaluate to some value. This also comes with > some nice benefits. > > You do not need to use {...} for anything that is a single statement. > But you can in each possible place use {...} to turn multiple > statements into one. > > Now think about a statement like this > > f <- function(n) { > x <- runif(n) > x**2 > } > > Then we can do > > y <- f(10) > > Now, you suggested way would look like this: > > f <- function(n) { > x <- runif(n) > y <- x**2 > } > > And we'd need to do something like: > > f(10) > y <- somehow_get_last_env_of_f$y > > So having a compound statement evaluate to a value clearly has a benefit. > > Best Regards, > Valentin > > 09.01.2023 18:05:58 akshay kulkarni <akshay_e4 at hotmail.com>: > > > Dear Valentin, > > But why should {....} "return" a value? It > could just as well evaluate all the expressions and store the > resulting objects in whatever environment the interpreter chooses, and > then it would be left to the user to manipulate any object he chooses. > Don't you think returning the last, or any value, is redundant? We are > living in the 21st century world, and the R-core team might,I suppose, > have a definite reason for"returning" the last value. Any comments? > > > > Thanking you, > > Yours sincerely, > > AKSHAY M KULKARNI > > > > ---------------------------------------- > > *From:* Valentin Petzel <valentin at petzel.at> > > *Sent:* Monday, January 9, 2023 9:18 PM > > *To:* akshay kulkarni <akshay_e4 at hotmail.com> > > *Cc:* R help Mailing list <r-help at r-project.org> > > *Subject:* Re: [R] return value of {....} > > > > Hello Akshai, > > > > I think you are confusing {...} with local({...}). This one will > evaluate the expression in a separate environment, returning the last > expression. > > > > {...} simply evaluates multiple expressions as one and returns the > result of the last line, but it still evaluates each expression. > > > > Assignment returns the assigned value, so we can chain assignments > > like > this > > > > a <- 1 + (b <- 2) > > > > conveniently. > > > > So when is {...} useful? Well, anyplace where you want to execute > complex stuff in a function argument. E.g. you might do: > > > > data %>% group_by(x) %>% summarise(y = {if(x[1] > 10) sum(y) else > mean(y)}) > > > > Regards, > > Valentin Petzel > > > > 09.01.2023 15:47:53 akshay kulkarni <akshay_e4 at hotmail.com>: > > > >> Dear members, > >> I have the following code: > >> > >>> TB <- {x <- 3;y <- 5} > >>> TB > >> [1] 5 > >> > >> It is consistent with the documentation: For {, the result of the > >> last > expression evaluated. This has the visibility of the last evaluation. > >> > >> But both x AND y are created, but the "return value" is y. How can > >> this > be advantageous for solving practical problems? Specifically, consider > the following code: > >> > >> F <- function(X) { expr; expr2; { expr5; expr7}; expr8;expr10} > >> > >> Both expr5 and expr7 are created, and are accessible by the code > outside of the nested braces right? But the "return value" of the > nested braces is expr7. So doesn't this mean that only expr7 should beaccessible?> Please help me entangle this (of course the return value of F is > expr10, and all the other objects created by the preceding expressions aredeleted.> But expr5 is not, after the control passes outside of the nested > braces!) > >> > >> Thanking you, > >> Yours sincerely, > >> AKSHAY M KULKARNI > >> > >> [[alternative HTML version deleted]] > >> > >> ______________________________________________ > >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > >> https://stat.ethz.ch/mailman/listinfo/r-help > >> PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > >> and provide commented, minimal, self-contained, reproducible code. > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]] ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.