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

Reply via email to