Stavros Macrakis wrote: > The documentation for assignment says: > > 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]]'). A syntactic name does not need to be quoted, though it > can be (preferably by backticks). > > But the implementation allows assignment to a character string (i.e. not a > name), which it coerces to a name: > > "foo" <- 23; foo > # returns 23 > > is.name("foo") > [1] FALSE > > Is this a documentation error or an implementation error? >
i think this concords with the documentation in the sense that in an assignment a string can work as a name. note that `foo bar` = 1 is.name(`foo`) # FALSE the issue is different here in that in is.name("foo") "foo" evaluates to a string (it works as a string literal), while in is.name(`foo`) `foo` evaluates to the value of the variable named 'foo' (with the quotes *not* belonging to the name). with only a quick look at the sources (src/main/envir.c:1511), i guess the first element to an assignment operator (i mean the left-assignment operators) is converted to a name, so that in "foo" <- 1 "foo" evaluates to a string and not a name (hence is.name("foo") is false), but internally it is sort of 'coerced' to a name, as in as.name("foo") # `foo` is.name(as.name("foo")) # TRUE > The coercion is not happening at parse time: > > class(quote("foo"<-3)[[2]]) > [1] "character" > i think the internal assignment op really receives a string in a case like "foo" <- 1, it knows it has to treat it as a name without the parser classifying the string as a name. (pure guesswork, again.) the documentation might avoid calling a plain string a 'quoted name', though, it is confusing. a quoted name is something like quote(name) or quote(`name`): is(quote(name)) # "name" "language" is(quote(`name`)) # "name" "language" but *not* something like "name": is("name") # "character" "vector" "data.frameRowLabels" and *not* like quote("name"): is(quote("name")) # "character" "vector" "data.frameRowLabels" > In fact, bizarrely, not only does it coerce to a name, it actually > *modifies* the parse tree: > > > gg <- quote("hij" <- 4) > > gg > "hij" <- 4 > > eval(gg) > > gg > hij <- 4 > wow! that's called 'functional programming' ;) you're right: gg = quote({"a" = 1}) is(gg[[2]][[2]]) # "character" ... eval(gg) is(gg[[2]][[2]]) # "name" ... > *** The cases below only come up with expression trees generated > programmatically as far as I know, so are much more marginal cases. *** > > The <- operator even allows the left-hand-side to be of length > 1, though > it just ignores the other elements, with the same side effect as before: > that's clear from the sources; see src/main/envir.c:1521. it should be documented (maybe it is, i haven't investigated this issue). > > gg <- quote(x<-44) > > gg[[2]] <- c("x","y") > > gg > c("x", "y") <- 44 > > eval(gg) but also this: rm(list=ls()) do.call('=', list(letters, 1)) # just fine a # 1 b # error weird these work. i think it deserves a warning, at the very least, as in c('x', 'y') = 4 # error: assignment to non-language object c(x, y) = 4 # error: could not find function c<- (provided that x and y are already there) btw., that's what you can do with rvalues (using the otherwise semantically void operator `:=`). these could seem equivalent, but they're (obviously) not: 'x' = 1 c('x') = 1 x = 1 c(x) = 1 > > x > [1] 44 > > y > Error: object "y" not found > > gg > x <- 44 > > None of this is documented in ? <-, and it is rather a surprise that > evaluating an expression tree can modify it. I admit we had a feature > (performance hack) like this in MacLisp years ago, where expanded syntax > macros replaced the source code of the macro, but it was a documented, > general, and optional part of the macro mechanism. > but - maclisp was designed by computer scientists in a research project, - r is being implemented by statisticians for practical purposes. almost every part differs here (and almost no pun intended). > Another little glitch: > > gg <- quote(x<-44); gg[[2]] <- character(0); eval(gg) > Error in eval(expr, envir, enclos) : > 'getEncChar' must be called on a CHARSXP > > This looks like an internal error that users shouldn't see. > by no means the only example that the interface is no blood-brain barrier. vQ ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel