[Rd] Unexpected behavior of identical() with language objects
Mark.Bravington at csiro.au
Mark.Bravington at csiro.au
Wed Oct 29 23:22:47 CET 2014
[See below for full email trail-- Outlook has beaten me into submission]
> I ran into this and found the result very surprising:
> identical( quote({ a }), quote({ a }) ) # FALSE
> <<...>>
> -Winston
> > Yes, looks like srcrefs are to blame:
> >
> > x <- quote({ a })
> > y <- quote({ a })
> >
> > identical(x, y)
> > # [1] FALSE
> <<...>>
> > Maybe identical() needs an ignore.srcref option? Normally when
> > comparing expressions or functions, you want to compare the code, not
> > it's textual representation.
> >
> > Hadley
What a great gotcha!
Seems to me it would be better to leave 'identical' alone and have a wrapper that you can call to strip any srcrefs. There is already 'utils::removeSource' but it doesn't work as-is with non-functions. The 5-minute hack below solves the particular example, but may well fall over with other cases--- not tested.
(This sort of thing reinforces my own feelings about 'srcref' as opposed to nice simple 'source'...)
Mark Bravington
CSIRO/Marine Lab/Hobart/Tas 7000/Australia
rmsrc <- function (fn) {
# based on utils::removeSource
is.fun <- is.function( fn)
if( (!is.fun && !is.language(fn)) || is.primitive(fn)) {
return(fn)
}
attr(fn, "source") <- NULL
attr(fn, "srcref") <- NULL
if( !is.fun) {
fn <- as.function( list( fn))
}
attr(body(fn), "wholeSrcref") <- NULL
attr(body(fn), "srcfile") <- NULL
recurse <- function(part) {
attr(part, "srcref") <- NULL
if (is.language(part) && is.recursive(part)) {
for (i in seq_along(part)) part[[i]] <- recurse(part[[i]])
}
part
}
body(fn) <- recurse(body(fn))
if( !is.fun) {
return( body( fn))
} else {
return( fn)
}
}
#> identical( rmsrc( quote({a})), rmsrc( quote({a})))
#[1] TRUE
> -----Original Message-----
> From: r-devel-bounces at r-project.org [mailto:r-devel-bounces at r-project.org]
> On Behalf Of Winston Chang
> Sent: Thursday, 30 October 2014 7:59 AM
> To: Hadley Wickham
> Cc: R Devel List
> Subject: Re: [Rd] Unexpected behavior of identical() with language objects
>
> Ah, I was using identical() to compare two function bodies. It returns
> FALSE even when you remove srcrefs from the body:
>
> f1 <- function(x) {
> if (TRUE) { x }
> }
> f2 <- function(x) {
> if (TRUE) { x }
> }
> f1b <- body(f1)
> f2b <- body(f2)
> attributes(f1b) <- NULL
> attributes(f2b) <- NULL
>
> # The bodies look the same with str()
> str(f1b)
> # language { if (TRUE) {; x; } }
> str(f2b)
> # language { if (TRUE) {; x; } }
>
> identical(f1b, f2b)
> # FALSE
>
>
>
> What I didn't realize was that the curly brace inside the body also
> independently captures srcrefs, but this isn't printed with str(f1b).
> However, str() on a more targeted part of the object reveals them:
> str(f1b[[2]][[3]])
> # length 2 { x }
> # - attr(*, "srcref")=List of 2
> # ..$ :Class 'srcref' atomic [1:8] 2 13 2 13 13 13 2 2
> # .. .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile'
> <environment: 0x452b2c0>
> # ..$ :Class 'srcref' atomic [1:8] 2 15 2 15 15 15 2 2
> # .. .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile'
> <environment: 0x452b2c0>
> # - attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment:
> 0x452b2c0>
> # - attr(*, "wholeSrcref")=Class 'srcref' atomic [1:8] 1 0 2 17 0 17 1 2
> # .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile'
> <environment: 0x452b2c0>
>
> -Winston
>
> On Wed, Oct 29, 2014 at 3:46 PM, Hadley Wickham <h.wickham at gmail.com>
> wrote:
> >>> Is this expected behavior? I can't seem to find anything in the help
> >>> for identical that relates to this.
> >>>
> >> It's not in ?identical, but ?Paren gives you some pointers.
> >> str(quote((a))) and str(quote({a})) are also informative.
> >
> > Yes, looks like srcrefs are to blame:
> >
> > x <- quote({ a })
> > y <- quote({ a })
> >
> > identical(x, y)
> > # [1] FALSE
> >
> > attr(x, "srcref") <- NULL
> > attr(x, "srcfile") <- NULL
> > attr(x, "wholeSrcref") <- NULL
> >
> > attr(y, "srcref") <- NULL
> > attr(y, "srcfile") <- NULL
> > attr(y, "wholeSrcref") <- NULL
> > identical(x, y)
> > # [1] TRUE
> >
> > Maybe identical() needs an ignore.srcref option? Normally when
> > comparing expressions or functions, you want to compare the code, not
> > it's textual representation.
> >
> > Hadley
> >
> > --
> > http://had.co.nz/
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
More information about the R-devel
mailing list