Bug 14031 - In the result of applying 'bquote' to function definition with 2 or more arguments, first function argument disappears
In the result of applying 'bquote' to function definition with 2 or more argu...
Status: CLOSED FIXED
Product: R
Classification: Unclassified
Component: Wishlist
old
ix86 (32-bit) Windows 32-bit
: P5 normal
Assigned To: Jitterbug compatibility account
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2009-10-29 11:33 UTC by Jitterbug compatibility account
Modified: 2009-11-06 22:42 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jitterbug compatibility account 2009-10-29 11:33:04 UTC
From: suharto_anggono@yahoo.com
Full_Name: Suharto Anggono
Version: 2.8.1
OS: Windows
Submission from: (NULL) (125.165.81.124)


Sorry for repost. There is already PR#9602, but the problem is still there.
There is also a post "Re: [R] using bquote to construct function" in R-help
2008-10-02.

This illustrates the problem.


C:\Program Files\R\R-2.8.1\bin>R --vanilla

R version 2.8.1 (2008-12-22)
Copyright (C) 2008 The R Foundation for Statistical Computing
ISBN 3-900051-07-0

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> h1 <- bquote(function(x, y) {
+ })
> h1
function(, y) {
}
> print(h1, useSource=FALSE)
function(, y) {
}
> eval(h1)
Error in eval(expr, envir, enclos) :
  invalid formal argument list for "function"
> h2 <- bquote(function(x, y) {})
> h2
function(x, y) {}

> print(h2, useSource=FALSE)
function(, y) {
}
> eval(h2)
Error in eval(expr, envir, enclos) :
  invalid formal argument list for "function"
> eval(bquote(function(x) {}))
function(x) {}
> eval(bquote(function() {}))
function() {}
> eval(bquote(function(...) {}))
function(...) {}
> eval(bquote(function(x, y, z) {}))
Error in eval(expr, envir, enclos) :
  invalid formal argument list for "function"
> version
               _
platform       i386-pc-mingw32
arch           i386
os             mingw32
system         i386, mingw32
status
major          2
minor          8.1
year           2008
month          12
day            22
svn rev        47281
language       R
version.string R version 2.8.1 (2008-12-22)
> sessionInfo()
R version 2.8.1 (2008-12-22)
i386-pc-mingw32

locale:
LC_COLLATE=English_United States.1252;LC_CTYPE=English_United
States.1252;LC_MON
ETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United
States.1252


attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base
>


R was installed from binary.

Above, h1 and h2 are results of applying 'bquote' to function definition with 2
arguments. Apparently, h1 and h2 are actually the same, just printed
differently. They are printed identically when useSource=FALSE. The first
argument disappears, error when 'eval'-ed.

But, apparently, if the function has one or zero argument, applying 'bquote'
results fine.


I try to debug. In the definition of 'bquote', there is 'unquote' function.


> bquote
function (expr, where = parent.frame())
{
    unquote <- function(e) {
        if (length(e) <= 1)
            e
        else if (e[[1]] == as.name("."))
            eval(e[[2]], where)
        else as.call(lapply(e, unquote))
    }
    unquote(substitute(expr))
}
<environment: namespace:base>
> unquote <- function(e) {
+ if (length(e) <= 1) e
+ else if (e[[1]] == as.name(".")) eval(e[[2]])
+ else as.call(lapply(e, unquote))
+ }
> h1e <- substitute(function(x, y) {
+ })
> unquote(h1e)
function(, y) {
}
> length(h1e)
[1] 4
> lapply(h1e, unquote)
[[1]]
`function`

[[2]]
``(y = )

[[3]]
{
}

[[4]]
"function(x, y) {"("}")

> as.call(.Last.value)
function(, y) {
}
> h1e[[2]]
$x


$y


> unquote(h1e[[2]])
``(y = )
> length(h1e[[2]])
[1] 2
> lapply(h1e[[2]], unquote)
$x


$y


> as.call(.Last.value)
``(y = )
>


After seeing the above result and reading the documentation of 'as.call', I
conclude that the first function argument (i.e. x) is missing because of
'as.call'. It should not be applied to the result for h1e[[2]]. However, it
should be applied to the result for h1e.


I don't know if this is worth to be fixed. But, if not, the documentation should
mention that 'bquote' is not to be applied to expression containing function
definition with two or more formal arguments.

Comment 1 Jitterbug compatibility account 2009-11-05 09:53:23 UTC
From: Suharto Anggono Suharto Anggono <suharto_anggono@yahoo.com>
This is a fix for 'bquote' that may work.

function (expr, where = parent.frame()) 
{
    unquote <- function(e) {
        if (length(e) <= 1 || !is.language(e)) 
            e
        else if (e[[1]] == as.name(".")) 
            eval(e[[2]], where)
        else as.call(lapply(e, unquote))
    }
    unquote(substitute(expr))
}



      Get your preferred Email name!
Now you can @ymail.com and @rocketmail.com. 
http://mail.promotions.yahoo.com/newdomains/aa/

Comment 2 Jitterbug compatibility account 2009-11-06 22:42:30 UTC
From: tlumley@u.washington.edu
On Thu, 5 Nov 2009, suharto_anggono@yahoo.com wrote:

> This is a fix for 'bquote' that may work.
>
> function (expr, where =3D parent.frame())=20
> {
>    unquote <- function(e) {
>        if (length(e) <=3D 1 || !is.language(e))=20
>            e
>        else if (e[[1]] =3D=3D as.name("."))=20
>            eval(e[[2]], where)
>        else as.call(lapply(e, unquote))
>    }
>    unquote(substitute(expr))
> }

If you want to use bquote() on function definitions a better fix is

bquote <- function (expr, where = parent.frame())
{
     unquote <- function(e) {
         if (length(e) <= 1)
             e
         else if (e[[1]] == as.name("."))
             eval(e[[2]], where)
         else if (is.pairlist(e)){
             as.pairlist(lapply(e,unquote))
         }
         else as.call(lapply(e, unquote))
     }
     unquote(substitute(expr))
}

since that now allows substitution into default arguments, eg
   default<-1
   g<-b2quote(function(x,y=.(default)) x+y )



         -thomas

Thomas Lumley			Assoc. Professor, Biostatistics
tlumley@u.washington.edu	University of Washington, Seattle

Comment 3 Jitterbug compatibility account 2009-11-18 14:33:00 UTC
NOTES:
 wish fulflled in 2.11.0
Comment 4 Jitterbug compatibility account 2009-11-18 14:33:41 UTC
Audit (from Jitterbug):
Wed Nov 18 08:33:41 2009	ripley	changed notes
Wed Nov 18 08:33:41 2009	ripley	moved from incoming to wishlst-fulfilled