[Rd] Conventions: Use of globals and main functions
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Tue Aug 27 11:36:32 CEST 2019
>>>>> 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 using gmail.com
>> <mailto:murdoch.duncan using 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 using r-project.org <mailto:R-devel using r-project.org> mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
More information about the R-devel
mailing list