[Rd] Assignment to string
Wacek Kusnierczyk
Waclaw.Marcin.Kusnierczyk at idi.ntnu.no
Wed Apr 1 23:11:26 CEST 2009
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
More information about the R-devel
mailing list