On 29/10/2014, 6:22 PM, mark.braving...@csiro.au wrote: > [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.
Sounds like utils::removeSource may need to be fixed, but until today I'd never heard any complaints about it. > (This sort of thing reinforces my own feelings about 'srcref' as opposed to > nice simple 'source'...) Nice simple 'source' can't do what srcrefs can do, for example report on locations during debugging, or when run-time errors occur. Duncan Murdoch > > 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-boun...@r-project.org [mailto:r-devel-boun...@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.wick...@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@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel