Duncan Murdoch wrote:> Scripts are for throwaways, not for anything worth keeping.I totally agree and have a tangentially relevant question about the <<- operator. Currently 'name <<- value' means to look up the environment stack until you find 'name' and (a) if you find 'name' in some frame bind it to a new value in that frame and (b) if you do not find it make a new entry for it in .GlobalEnv. Should R deprecate the second part of that and give an error if 'name' is not already present in the environment stack? This would catch misspelling errors in functions that collect results from recursive calls. E.g., collectStrings <- function(list) { strings <- character() # to be populated by .collect .collect <- function(x) { if (is.list(x)) { lapply(x, .collect) } else if (is.character(x)) { strings <<- c(strings, x) } misspelledStrings <<- c(strings, names(x)) # oops, would like to be told about this error NULL } .collect(list) strings } This gives the incorrect:> collectStrings(list(i="One", ii=list(a=1, b="Two")))[1] "One" "Two"> misspelledStrings[1] "One" "Two" "i" "ii" instead of what we would get if 'misspelledStrings' were 'strings'.> collectStrings(list(i="One", ii=list(a=1, b="Two")))[1] "One" "Two" "a" "b" "i" "ii" If someone really wanted to assign into .GlobalEnv the assign() function is available. In S '<<-' only had meaning (b) and R added meaning (a). Perhaps it is time to drop meaning (b). We could start by triggering a warning about it if some environment variable were set, as is being done for non-scalar && and ||. Bill Dunlap TIBCO Software wdunlap tibco.com On Sun, Aug 25, 2019 at 5:09 PM Duncan Murdoch <murdoch.duncan at gmail.com> wrote:> On 25/08/2019 7:09 p.m., Cyclic Group Z_1 wrote: > > > > > > This is a fair point; structuring functions into packages is probably > ultimately the gold standard for code organization in R. However, lexical > scoping in R is really not much different than in other languages, such as > Python, in which use of main functions and defining other named functions > outside of main are encouraged. For example, in Scheme, from which R > derives its scoping rules, the community generally organizes code with > almost exclusively functions and few non-function global variables at top > level. The common use of globals in R seems to be mostly a consequence of > historical interactive use and, relatedly, an inherited practice from S. > > > > It is true, though, that since anonymous functions (such as in lapply) > play a large part in idiomatic R code, as you put it, "[l]exical scoping > means that all of the problems of global variables are available to writers > who use main()." Nevertheless, using a main function with other functions > defined outside it seems like a good quick alternative that offers similar > advantages to making a package when functions are tightly coupled to the > script and the project may not be large or generalizable enough to warrant > making a package. > > > > I think the idea that making a package is too hard is just wrong. > Packages in R have lots of requirements, but nowadays there are tools > that make them easy. Eleven years ago at UseR in Dortmund I wrote a > package during a 45 minute presentation, and things are much easier now. > > If you make a complex project without putting most of the code into a > package, you don't have something that you will be able to modify in a > year or two, because you won't have proper documentation. > > Scripts are for throwaways, not for anything worth keeping. > > Duncan Murdoch > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >[[alternative HTML version deleted]]
On 26/08/2019 1:58 p.m., William Dunlap wrote:> Duncan Murdoch wrote: > > Scripts are for throwaways, not for anything worth keeping. > > I totally agree and have a tangentially relevant question about the <<- > operator.? Currently 'name <<- value' means to look up the environment > stack until you find 'name'? and (a) if you find 'name' in some frame > bind it to a new value in that frame and (b) if you do not find it make > a new entry for it in .GlobalEnv. > > Should R deprecate the second part of that and give an error if 'name' > is not already present in the environment stack?? This would catch > misspelling errors in functions that collect results from recursive > calls.? E.g.,I like that suggestion. Package tests have been complaining about packages writing to .GlobalEnv for a while now, so there probably aren't many instances of b) in CRAN packages; that change might be relatively painless. Duncan Murdoch> > collectStrings <- function(list) { > ? ? strings <- character() # to be populated by .collect > ? ? .collect <- function(x) { > ? ? ? ? if (is.list(x)) { > ? ? ? ? ? ? lapply(x, .collect) > ? ? ? ? } else if (is.character(x)) { > ? ? ? ? ? ? strings <<- c(strings, x) > ? ? ? ? } > ? ? ? ? misspelledStrings <<- c(strings, names(x)) # oops, would like > to be told about this error > ? ? ? ? NULL > ? ? } > ? ? .collect(list) > ? ? strings > } > > This gives the incorrect: > > collectStrings(list(i="One", ii=list(a=1, b="Two"))) > [1] "One" "Two" > > misspelledStrings > [1] "One" "Two" "i" ? "ii" > > instead of what we would get if 'misspelledStrings' were 'strings'. > > collectStrings(list(i="One", ii=list(a=1, b="Two"))) > [1] "One" "Two" "a" ? "b" ? "i" ? "ii" > > If someone really wanted to assign into .GlobalEnv the assign() function > is available. > > In S '<<-' only had meaning (b) and R added meaning (a).? Perhaps it is > time to drop meaning (b).? We could start by triggering a warning about > it if some environment variable were set, as is being done for > non-scalar && and ||. > > Bill Dunlap > TIBCO Software > wdunlap tibco.com <http://tibco.com> > > > On Sun, Aug 25, 2019 at 5:09 PM Duncan Murdoch <murdoch.duncan at gmail.com > <mailto:murdoch.duncan at gmail.com>> wrote: > > On 25/08/2019 7:09 p.m., Cyclic Group Z_1 wrote: > > > > > > This is a fair point; structuring functions into packages is > probably ultimately the gold standard for code organization in R. > However, lexical scoping in R is really not much different than in > other languages, such as Python, in which use of main functions and > defining other named functions outside of main are encouraged. For > example, in Scheme, from which R derives its scoping rules, the > community generally organizes code with almost exclusively functions > and few non-function global variables at top level. The common use > of globals in R seems to be mostly a consequence of historical > interactive use and, relatedly, an inherited practice from S. > > > > It is true, though, that since anonymous functions (such as in > lapply) play a large part in idiomatic R code, as you put it, > "[l]exical scoping means that all of the problems of global > variables are available to writers who use main()." Nevertheless, > using a main function with other functions defined outside it seems > like a good quick alternative that offers similar advantages to > making a package when functions are tightly coupled to the script > and the project may not be large or generalizable enough to warrant > making a package. > > > > I think the idea that making a package is too hard is just wrong. > Packages in R have lots of requirements, but nowadays there are tools > that make them easy.? Eleven years ago at UseR in Dortmund I wrote a > package during a 45 minute presentation, and things are much easier now. > > If you make a complex project without putting most of the code into a > package, you don't have something that you will be able to modify in a > year or two, because you won't have proper documentation. > > Scripts are for throwaways, not for anything worth keeping. > > Duncan Murdoch > > ______________________________________________ > R-devel at r-project.org <mailto:R-devel at r-project.org> mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >
>>>>> Duncan Murdoch >>>>> on Mon, 26 Aug 2019 14:19:36 -0400 writes:> On 26/08/2019 1:58 p.m., William Dunlap wrote: >> Duncan Murdoch wrote: >> > Scripts are for throwaways, not for anything worth keeping. >> >> I totally agree and have a tangentially relevant question about the <<- >> operator.? Currently 'name <<- value' means to look up the environment >> stack until you find 'name'? and (a) if you find 'name' in some frame >> bind it to a new value in that frame and (b) if you do not find it make >> a new entry for it in .GlobalEnv. >> >> Should R deprecate the second part of that and give an error if 'name' >> is not already present in the environment stack?? This would catch >> misspelling errors in functions that collect results from recursive >> calls.? E.g., > I like that suggestion. Package tests have been complaining about > packages writing to .GlobalEnv for a while now, so there probably aren't > many instances of b) in CRAN packages; that change might be relatively > painless. > Duncan Murdoch I don't agree currently : AFAICS, there's no other case (in S or) R where an assignment only works if there's no object with that name. In addition: If I wanted such a functionality I'd rather have with a function that has several arguments and this behavior was switchable via <argname> = TRUE/FALSE , rather than with `<<-` which has always exactly 2 arguments. [This is my personal opinion only; other R Core members may well think differently about this] Martin >> collectStrings <- function(list) { >> ? ? strings <- character() # to be populated by .collect >> ? ? .collect <- function(x) { >> ? ? ? ? if (is.list(x)) { >> ? ? ? ? ? ? lapply(x, .collect) >> ? ? ? ? } else if (is.character(x)) { >> ? ? ? ? ? ? strings <<- c(strings, x) >> ? ? ? ? } >> ? ? ? ? misspelledStrings <<- c(strings, names(x)) # oops, would like >> to be told about this error >> ? ? ? ? NULL >> ? ? } >> ? ? .collect(list) >> ? ? strings >> } >> >> This gives the incorrect: >> > collectStrings(list(i="One", ii=list(a=1, b="Two"))) >> [1] "One" "Two" >> > misspelledStrings >> [1] "One" "Two" "i" ? "ii" >> >> instead of what we would get if 'misspelledStrings' were 'strings'. >> > collectStrings(list(i="One", ii=list(a=1, b="Two"))) >> [1] "One" "Two" "a" ? "b" ? "i" ? "ii" >> >> If someone really wanted to assign into .GlobalEnv the assign() function >> is available. >> >> In S '<<-' only had meaning (b) and R added meaning (a).? Perhaps it is >> time to drop meaning (b).? We could start by triggering a warning about >> it if some environment variable were set, as is being done for >> non-scalar && and ||. >> >> Bill Dunlap >> TIBCO Software >> wdunlap tibco.com <http://tibco.com> >> >> >> On Sun, Aug 25, 2019 at 5:09 PM Duncan Murdoch <murdoch.duncan at gmail.com >> <mailto:murdoch.duncan at gmail.com>> wrote: >> >> On 25/08/2019 7:09 p.m., Cyclic Group Z_1 wrote: >> > >> > >> > This is a fair point; structuring functions into packages is >> probably ultimately the gold standard for code organization in R. >> However, lexical scoping in R is really not much different than in >> other languages, such as Python, in which use of main functions and >> defining other named functions outside of main are encouraged. For >> example, in Scheme, from which R derives its scoping rules, the >> community generally organizes code with almost exclusively functions >> and few non-function global variables at top level. The common use >> of globals in R seems to be mostly a consequence of historical >> interactive use and, relatedly, an inherited practice from S. >> > >> > It is true, though, that since anonymous functions (such as in >> lapply) play a large part in idiomatic R code, as you put it, >> "[l]exical scoping means that all of the problems of global >> variables are available to writers who use main()." Nevertheless, >> using a main function with other functions defined outside it seems >> like a good quick alternative that offers similar advantages to >> making a package when functions are tightly coupled to the script >> and the project may not be large or generalizable enough to warrant >> making a package. >> > >> >> I think the idea that making a package is too hard is just wrong. >> Packages in R have lots of requirements, but nowadays there are tools >> that make them easy.? Eleven years ago at UseR in Dortmund I wrote a >> package during a 45 minute presentation, and things are much easier now. >> >> If you make a complex project without putting most of the code into a >> package, you don't have something that you will be able to modify in a >> year or two, because you won't have proper documentation. >> >> Scripts are for throwaways, not for anything worth keeping. >> >> Duncan Murdoch >> >> ______________________________________________ >> R-devel at r-project.org <mailto:R-devel at r-project.org> mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel