Bug 16215 - If x is a call, in mode(x) <- "list", the call is evaluated
Summary: If x is a call, in mode(x) <- "list", the call is evaluated
Status: CLOSED FIXED
Alias: None
Product: R
Classification: Unclassified
Component: Language (show other bugs)
Version: R 3.1.2
Hardware: ix86 (32-bit) Windows 32-bit
: P5 minor
Assignee: R-core
URL:
Depends on:
Blocks:
 
Reported: 2015-02-18 18:02 UTC by Suharto Anggono
Modified: 2015-02-19 14:55 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Suharto Anggono 2015-02-18 18:02:18 UTC
This is an example from R FAQ 7.33.

> as.list(quote(-2^2))
[[1]]
`-`

[[2]]
2^2


Below, similar thing is tried by using mode(x) <- "list" .

> x <- quote(-2^2)
> x
-2^2
> mode(x) <- "list"
> x
[[1]]
[1] -4


The result is not as expected.

Using storage.mode(x) <- "list" gives the expected result.

> x <- quote(-2^2)
> storage.mode(x) <- "list"
> x
[[1]]
`-`

[[2]]
2^2



The responsible part in the definition of function 'mode<-' is the following.
    x <- eval(call(mde, x), parent.frame())

With 'mde' is "as.list" and 'x' is a call, when 'eval' is done, 'as.list' works on the result of evaluating the call in 'x'.

A possible fix is using
    x <- eval(call(mde, as.name("x")), list(x = x), parent.frame())


> sessionInfo()
R version 3.1.2 (2014-10-31)
Platform: i386-w64-mingw32/i386 (32-bit)

locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base
Comment 1 Duncan Murdoch 2015-02-19 12:23:08 UTC
Your suggested fix won't work (it evaluates x in the wrong frame, so if the argument isn't x, things will go wrong), but I think this one should:

x <- eval(call(mde, substitute(x)), parent.frame())

Will test and commit to R-devel if it looks okay.
Comment 2 Duncan Murdoch 2015-02-19 13:11:01 UTC
My fix doesn't work either.  This needs a deeper fix:  sometimes `mode<-` will be called with an argument named *tmp*, and the substitute will fail.

I don't think I'll have time for this in the next week or two, so I'll leave it for others...
Comment 3 Luke Tierney 2015-02-19 14:29:53 UTC
Wouldn't somehting along the lines of

mde <- get(paste0("as.", value), mode = "function")
x <- mde(x)

make more sense? (have get look in parent.frame if you like)
Comment 4 Suharto Anggono 2015-02-19 14:54:20 UTC
(In reply to Duncan Murdoch from comment #1)
> Your suggested fix won't work (it evaluates x in the wrong frame, so if the
> argument isn't x, things will go wrong), but I think this one should:
> 
> x <- eval(call(mde, substitute(x)), parent.frame())
> 
> Will test and commit to R-devel if it looks okay.

    x <- eval(call(mde, as.name("x")), list(x = x), parent.frame())

Above, list(x = x) is supplied as the "environment". So, in my understanding, it would be searched first and the name 'x' would refer to its 'x' component.
Comment 5 Duncan Murdoch 2015-02-19 14:55:30 UTC
Luke's suggestion works.  I'll commit it soon to R-devel and R-patched.