I was trying to create a function with a value computed at creation time, using substitute(), but I got results I don't understand: > this.is.R Error: Object "this.is.R" not found > substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]]))) this.is.R <- function() TRUE > # the above expression as printed is what I want for the function definition > eval(substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]])))) > this.is.R function() X > this.is.R() [1] TRUE > X Error: Object "X" not found > rm(this.is.R) > # Try again a slightly different way > substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]]))) this.is.R <- function() TRUE > .Last.value this.is.R <- function() TRUE > eval(.Last.value) > this.is.R function() X > this.is.R() [1] TRUE > rm(this.is.R) > Why is the body of the function "X" when I substituted a different expression for X? Also, given that the body of the function is X, how does the function evaluate to TRUE since X is not defined anywhere (except in a list that should have been discarded.) This happens with both R 1.7.1 and R 1.8.0 (under Windows 2000). (yes, I did discover the function is.R(), but I still want to discover what's going here.) -- Tony Plate PS. In S-plus 6.1, things worked as I had expected: > substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]]))) this.is.R <- function() F > eval(substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]])))) function() F > this.is.R function() F > this.is.R() [1] F >
Tony Plate <tplate at blackmesacapital.com> writes:> Why is the body of the function "X" when I substituted a different > expression for X? Also, given that the body of the function is X, how > does the function evaluate to TRUE since X is not defined anywhere > (except in a list that should have been discarded.) > > This happens with both R 1.7.1 and R 1.8.0 (under Windows 2000). > > (yes, I did discover the function is.R(), but I still want to discover > what's going here.)I think you are defeating the keep.source mechanism. What you're seeing is not the actual function but its source attribute. Try attributes(this.is.R) <- NULL and see what happens. -- O__ ---- Peter Dalgaard Blegdamsvej 3 c/ /'_ --- Dept. of Biostatistics 2200 Cph. N (*) \(*) -- University of Copenhagen Denmark Ph: (+45) 35327918 ~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk) FAX: (+45) 35327907
Peter, thank you for the explanation. This is indeed what is happening. Might I suggest the following passage for inclusion in the help page for "function", and possibly also "body", in the DETAILS or WARNING section: "Note that the text of the original function definition is saved as an attribute "source" on the function, and this is printed out when the function is printed. Hence, if the function body is changed in some way other than by assigning a value via body() (which removes the "source" attribute), the printed form of the function may not be the same as the actual function body." Something along these lines could also go in the help for "eval", though if it were only there it might be very difficult to find. Here is a transcript that shows what is happening, with another suggestion following it. > eval(substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]])))) > this.is.R function() X > body(this.is.R) [1] TRUE > attributes(this.is.R) $source [1] "function() X" > attributes(this.is.R) <- NULL > this.is.R function () TRUE > # the "source" attribute comes from function definition: > attributes(function() X) $source [1] "function() X" > # and seems to be added by "eval": > attr(eval(parse(text="function() TRUE")[[1]]), "source") [1] "function() TRUE" > > # we can assign bogus "source" > attr(this.is.R, "source") <- "a totally bogus function body" > this.is.R a totally bogus function body > # assigning to body() removes "source" > body(this.is.R) <- list(666) > this.is.R function () 666 > attr(this.is.R, "source") NULL > An even better approach might be something that gave a warning on printing if the parsed "source" attribute was not identical to the language object being printed. This would probably belong in the code for "case LANGSXP:" in the function PrintValueRec in main/print.c (if it were written in R, I could contribute a patch, but right now I don't have time to try to understand the C there.) R code to do the test could be something like this: > f <- this.is.R > identical(f, eval(parse(text=attr(f, "source"))[[1]])) [1] FALSE > f <- function() TRUE > identical(f, eval(parse(text=attr(f, "source"))[[1]])) [1] TRUE > -- Tony Plate At Thursday 09:12 PM 10/23/2003 +0200, Peter Dalgaard wrote:>Tony Plate <tplate at blackmesacapital.com> writes: > > > Why is the body of the function "X" when I substituted a different > > expression for X? Also, given that the body of the function is X, how > > does the function evaluate to TRUE since X is not defined anywhere > > (except in a list that should have been discarded.) > > > > This happens with both R 1.7.1 and R 1.8.0 (under Windows 2000). > > > > (yes, I did discover the function is.R(), but I still want to discover > > what's going here.) > >I think you are defeating the keep.source mechanism. What you're >seeing is not the actual function but its source attribute. Try >attributes(this.is.R) <- NULL and see what happens. > >-- > O__ ---- Peter Dalgaard Blegdamsvej 3 > c/ /'_ --- Dept. of Biostatistics 2200 Cph. N > (*) \(*) -- University of Copenhagen Denmark Ph: (+45) 35327918 >~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk) FAX: (+45) 35327907
[resent the next day, after not appearing on the list] Peter, thank you for the explanation. This is indeed what is happening. Might I suggest the following passage for inclusion in the help page for "function", and possibly also "body", in the DETAILS or WARNING section: "Note that the text of the original function definition is saved as an attribute "source" on the function, and this is printed out when the function is printed. Hence, if the function body is changed in some way other than by assigning a value via body() (which removes the "source" attribute), the printed form of the function may not be the same as the actual function body." Something along these lines could also go in the help for "eval", though if it were only there it might be very difficult to find if one were trying to look up puzzling behavior of a function. Here is a transcript that shows what is happening, with another suggestion following it. > eval(substitute(this.is.R <- function() X, list(X=!is.null(options("CRAN")[[1]])))) > this.is.R function() X > body(this.is.R) [1] TRUE > attributes(this.is.R) $source [1] "function() X" > attributes(this.is.R) <- NULL > this.is.R function () TRUE > # the "source" attribute comes from function definition: > attributes(function() X) $source [1] "function() X" > # and seems to be added by "eval": > attr(eval(parse(text="function() TRUE")[[1]]), "source") [1] "function() TRUE" > > # we can assign bogus "source" > attr(this.is.R, "source") <- "a totally bogus function body" > this.is.R a totally bogus function body > # assigning to body() removes "source" > body(this.is.R) <- list(666) > this.is.R function () 666 > attr(this.is.R, "source") NULL > An even better approach might be something that gave a warning on printing if the parsed "source" attribute was not identical to the language object being printed. This would probably belong in the code for "case LANGSXP:" in the function PrintValueRec in main/print.c (if it were written in R, I could contribute a patch, but right now I don't have time to try to understand the C there.) R code to do the test could be something like this: > f <- this.is.R > identical(f, eval(parse(text=attr(f, "source"))[[1]])) [1] FALSE > f <- function() TRUE > identical(f, eval(parse(text=attr(f, "source"))[[1]])) [1] TRUE > -- Tony Plate At Thursday 09:12 PM 10/23/2003 +0200, Peter Dalgaard wrote:>Tony Plate <tplate at blackmesacapital.com> writes: > > > Why is the body of the function "X" when I substituted a different > > expression for X? Also, given that the body of the function is X, how > > does the function evaluate to TRUE since X is not defined anywhere > > (except in a list that should have been discarded.) > > > > This happens with both R 1.7.1 and R 1.8.0 (under Windows 2000). > > > > (yes, I did discover the function is.R(), but I still want to discover > > what's going here.) > >I think you are defeating the keep.source mechanism. What you're >seeing is not the actual function but its source attribute. Try >attributes(this.is.R) <- NULL and see what happens. > >-- > O__ ---- Peter Dalgaard Blegdamsvej 3 > c/ /'_ --- Dept. of Biostatistics 2200 Cph. N > (*) \(*) -- University of Copenhagen Denmark Ph: (+45) 35327918 >~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk) FAX: (+45) 35327907