For reasons which I'll spare you, I'm writing a program to analyse R source code. This has led me to probe some of the darker corners of R syntax to find out what is supposed to happen. Now, from reading the R documentation (and the New S book &c) I know perfectly well that f(a, b, etc) <- x is supposed to turn into a <- "f<-"(a, b, etc, value=x) Except, what if f is not an identifier or string? What, for example, should _this_ do?> x <- NULL > (if (TRUE) names else dim)(x) <- 27I was expecting _either_ that I would be told that you can't set names(NULL) to 27, _or_ that I would be told the whole thing wasn't allowed. In fact, it was allowed.> x[1] 27 This result has me completely baffled. Is this behaviour intentional? What rules does it follow from? What _exactly_ are the rules for assignment supposed to be _in R_? The emphasis on _in R_ is because I know the New S book spells out a lot of detail, but (a) I've been searching for my copy for a couple of weeks and (b) R is not _exactly_ the same as S.
On Tue, 2 Sep 2003, Richard A. O'Keefe wrote:> For reasons which I'll spare you, I'm writing a program to analyse > R source code. This has led me to probe some of the darker corners > of R syntax to find out what is supposed to happen. > > Now, from reading the R documentation (and the New S book &c) I know > perfectly well that > f(a, b, etc) <- x > is supposed to turn into > a <- "f<-"(a, b, etc, value=x) > > Except, what if f is not an identifier or string? > What, for example, should _this_ do? > > > x <- NULL > > (if (TRUE) names else dim)(x) <- 27 > > I was expecting _either_ that I would be told that you can't > set names(NULL) to 27, _or_ that I would be told the whole thing > wasn't allowed.I get Error: couldn't find function " <-" ! (On some systems I get a set of non-printable chars in there.) What I would have expected is that it tried to find "(<-" and failed, as in> x <- 3 > (names(x)) <- 27Error: couldn't find function "(<-" (and S does essentially that in your example).> In fact, it was allowed. > > > x > [1] 27 > > This result has me completely baffled.Not reproducible, either.> Is this behaviour intentional? > What rules does it follow from? > What _exactly_ are the rules for assignment supposed to be _in R_? > > The emphasis on _in R_ is because I know the New S book spells out > a lot of detail, but (a) I've been searching for my copy for a couple > of weeks and (b) R is not _exactly_ the same as S.And for R you have the source code, and a `R Language Definition'. -- Brian D. Ripley, ripley at stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272866 (PA) Oxford OX1 3TG, UK Fax: +44 1865 272595
I asked what> x <- NULL > (if (TRUE) names else dim)(x) <- 27is *supposed* to do. Professor Brian Ripley basically gave me the answer I wanted: it isn't *supposed* to do anything. However, he went on to say And for R you have the source code, and a `R Language Definition'. My original message made it clear that I had read the R documentation. I am very favourably impressed by it; compared with many commercial systems it is *superb*. However, the R Language Definition is not finished yet and does not discuss assignment at length. In fact, remarks on assignment are scattered thinly throughout the text, at least one appears to have "right" when it means "left". That's OK; it doesn't claim to be finished documentation, but it does mean that some questions cannot as yet be answered by reading it. As for the code (src/main/eval.c), it tells you want DOES happen (if you are considerably more familiar with R internals than I am yet), but with R's characteristic paucity of comments, it says nothing about what is *supposed* to happen. By the way, is anyone else worried about this code: static SEXP applydefine(SEXP call, SEXP op, SEXP args, SEXP rho) { ... =======>char buf[32]; ... while (isLanguage(CADR(expr))) { ===========>sprintf(buf, "%s<-", CHAR(PRINTNAME(CAR(expr)))); tmp = install(buf); A similar buffer-overrun in Windows RTF boxes led to a security vulnerability. To put it another way, it was a serious question for a serious reason, and I _had_ done my homework, but I have a really hard time reading the R sources.
On Tue, 2 Sep 2003, Richard A. O'Keefe wrote:> For reasons which I'll spare you, I'm writing a program to analyse > R source code. This has led me to probe some of the darker corners > of R syntax to find out what is supposed to happen. > > Now, from reading the R documentation (and the New S book &c) I know > perfectly well that > f(a, b, etc) <- x > is supposed to turn into > a <- "f<-"(a, b, etc, value=x) > > Except, what if f is not an identifier or string? > What, for example, should _this_ do? > > > x <- NULL > > (if (TRUE) names else dim)(x) <- 27 > > I was expecting _either_ that I would be told that you can't > set names(NULL) to 27, _or_ that I would be told the whole thing > wasn't allowed. > > In fact, it was allowed. > > > x > [1] 27 > > This result has me completely baffled. > > Is this behaviour intentional?No. Using anything other than a symbol or string for the function in a complex assignment is an error. The internals assumed the function would be a symbol (the parser deals with the string case) but did not check for this; should be fixed shortly in R-devel. Thanks for pointing this out. luke -- Luke Tierney University of Iowa Phone: 319-335-3386 Department of Statistics and Fax: 319-335-3017 Actuarial Science 241 Schaeffer Hall email: luke at stat.uiowa.edu Iowa City, IA 52242 WWW: http://www.stat.uiowa.edu
Please choose answer: a) you beat me to it making a great point b) it's got two too many pairs of braces in it, that's whats wrong with it! But seriously, I am sure Richard O'K had no intention of doing any such thing. The question was just about the syntax of R, no? Isn't it the case that (expr)(expr) is incorrect syntax under any circumstances?> -----Original Message----- > From: Barry Rowlingson [mailto:B.Rowlingson at lancaster.ac.uk] > please nooooo!!! What's wrong with: > > if(cond){ > names(x) <- 10 > } else { > dim(x) <- 10 > } >Simon Fear Senior Statistician Syne qua non Ltd Tel: +44 (0) 1379 644449 Fax: +44 (0) 1379 644445 email: Simon.Fear at synequanon.com web: http://www.synequanon.com Number of attachments included with this message: 0 This message (and any associated files) is confidential and\...{{dropped}}
> -----Original Message----- > From: Simon Fear [mailto:Simon.Fear at synequanon.com] > Sent: 02 September 2003 17:19 > To: Barry Rowlingson; Peter Dalgaard BSA > Cc: r-help at r-project.org > Subject: RE: [R] I don't understand this> Isn't it the case that > > (expr)(expr) > > is incorrect syntax under any circumstances?No, you could have a function definition on the left:> (function(x)x^2)(2)[1] 4 HTH Thomas --- Thomas Hotz Research Associate in Medical Statistics University of Leicester United Kingdom Department of Epidemiology and Public Health 22-28 Princess Road West Leicester LE1 6TP Tel +44 116 252-5410 Fax +44 116 252-5423 Division of Medicine for the Elderly Department of Medicine The Glenfield Hospital Leicester LE3 9QP Tel +44 116 256-3643 Fax +44 116 232-2976
Thomas Lumley <tlumley at u.washington.edu> wrote: I would have said that the behavior of (if (cond) names else dim)(x) <- 10 is undefined in the S language, along with things like the order of evaluation of the apply functions. The thing is, it would make perfect sense for (if (cond) f else g)(x) <- e to have the effect of (if (cond) f(x) <- e else g(x) <- e) In fact, I've used two programming languages where the analogue of this _did_ work, and a third where it didn't but using only published interfaces could very easily be made to work. Another assignment-related thing I'm not clear on is what f(x) <<- e is supposed to do. f(x) <- e is equivalent to x <- "f<-"(x, value=e) and x <<- e assigns to x in the next outer environment, but a simple macro-expansion of f(x) <<- e to x <<- "f<-"(x, value=e) may have the nasty effect of writing to an outer x a value derived from an inner one. Now, that seems to be exactly what happens in R:> x <- c(1,2,3) > f <- function(x) x[2] <<- x > f(77) > x[1] 77 77 While the documentation and source code _could_ tell me whether this is intentional, as far as I can tell (and I have, needless to say, looked) they _don't_. Now, despite its misleading opening screen (which says that the target of an assignment is "a variable name (possibly quoted)", ?"<<-" goes on to say that vvv In all the assignment operator expressions, `x' can be a name or ^^^ an expression defining a part of an object to be replaced (e.g., `z[[1]]'). The name does not need to be quoted, though it can be. (the arrows are my emphasis.) So it's explict that f(x) <<- e is *supposed* to be allowed and I don't need to ask about that. The question is, what is f(x) <<- e supposed to do when there is an x in the current environment as well as one in an outer environment? It doesn't make much sense to fetch from one variable and store into the other, but that's what R actually does. Is that really what's *supposed* to happen? It would be perfectly possible to make f(x) <<- e use the same variable in both places, and since the form is accepted by R, I expected it to work that way. Perhaps the simplest alternative that would still allow this form to be used in non-confusing cases would be to issue an error message if x is defined in the local environment; if it isn't, the simple macro expansion will work just fine.> x <- c(1,2,3) > f <- function(y) x[2] <<- y > f(77) > x[1] 1 77 3 This example works as ?"<<-" might lead one to expect.
"Simon Fear" <Simon.Fear at synequanon.com> wrote: But seriously, I am sure Richard O'K had no intention of doing any such thing. The question was just about the syntax of R, no? Exactly so. Isn't it the case that (expr)(expr) is incorrect syntax under any circumstances? No. Functions are values in R, just like they are in C and Scheme. And R accepts expressions in function position, just as C and Scheme do.> (sqrt)(4)[1] 2> f <- c(sin,cos) > f[[1]](0)[1] 0> f[[2]](0)[1] 1 Beware: f[1] and f[2] are lists, not functions; they don't work.> (if (TRUE) cos else sin)(0)[1] 1> (if (FALSE) cos else sin)(0)[1] 0 Not only is this all allowed by R's parser, it works just fine. Why _should_ it be a syntax error? There's one difference between f(x) and (f)(x). The first is basically get("f", mode="function")(x) while the second is basically get("f", mode="any")(x). A couple of times this has kept me out of trouble when I've unwittingly used c as a local numeric variable AND as the column constructor function. I'm not entirely sure that I'm grateful for this; I never _meant_ to do any such thing and I'd rather have been told about my mistake. But that interpretation of f(x) is clearly described in the New S book.
Thanks to everyone for enlightening me about (f)(g). So I suppose (f)(g)(h)... is OK as long as (f)(g) returns a function with an argument (and so on)? Meanwhile, back on Earth, in attempting a compromise between the clarity of Barry R's if (cond) names(x) <- 10 else dim(x) <- 10 and the generality of Peter D's eval(substitute(foo(x)<-10,list(foo=as.name(if (cond) "names" else "dim")))) I tried to set it up as a clearer two-liner: foo <- if (cond) names else dim foo(x) <- 10> foo <- if (TRUE) names else dim > foofunction (x) UseMethod("names") <environment: namespace:base> So far so good. But> foo(x) <- 10Error: couldn't find function "foo<-" Shedding further light on the semantic problem with the construct "f(x)<-"; it will only work if "f<-" is already explicitly defined, in addition to "f" being defined. (Or if "<-" has had its default overwritten.) Making "foo" equivalent to "names" does not make "foo<-" equivalent to "names<-". You need an on-the-fly explicit eval(substitute(...)) to do that. The same should hold for "(f)(x)<-" except that (f) might find a non-function value; I would expect (and hope) for a crash if so. Sorry if this is obvious to many people on the list. It has been a very enlightening discussion for me. At least, I thought I was learning something, until at the next prompt I experimented with> (foo)(x) <- 10Error: couldn't find function "H-?<-" Now where did THAT error message come from?? (I am running R version 0.1 on a PDP 8. Same result with 1.7.0 under Win98) Simon Fear Senior Statistician Syne qua non Ltd Tel: +44 (0) 1379 644449 Fax: +44 (0) 1379 644445 email: Simon.Fear at synequanon.com web: http://www.synequanon.com Number of attachments included with this message: 0 This message (and any associated files) is confidential and\...{{dropped}}