S3 method dispatch for methods in local environments

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

S3 method dispatch for methods in local environments

Wolfgang Viechtbauer-2
Dear All,

In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example:

myfun <- function(y) {
   out <- list(y=y)
   class(out) <- "myclass"
   return(out)
}

print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5))

myfun(1:4)

# prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"

rm(print.myclass)
myenv <- new.env()
myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv)
attach(myenv)
myfun(1:4)

# still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"

But since R 4.0.0, this no longer words and the above prints:

$y
[1] 1 2 3 4

attr(,"class")
[1] "myclass"

Is this intended? And is there a way to still make this work?

Best,
Wolfgang

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: S3 method dispatch for methods in local environments

Martin Maechler
>>>>> Viechtbauer, Wolfgang (SP)
>>>>>     on Tue, 12 May 2020 18:05:32 +0000 writes:

    > Dear All,
    > In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example:

    > myfun <- function(y) {
    > out <- list(y=y)
    > class(out) <- "myclass"
    > return(out)
    > }

    > print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5))

    > myfun(1:4)

    > # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"

    > rm(print.myclass)
    > myenv <- new.env()
    > myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv)
    > attach(myenv)
    > myfun(1:4)

    > # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"

    > But since R 4.0.0, this no longer words and the above prints:

    > $y
    > [1] 1 2 3 4

    > attr(,"class")
    > [1] "myclass"

    > Is this intended?

yes, most probably, unless

    > And is there a way to still make this work?

Using  the new

       .S3method(<generic>, <class>, <method_function>)

had been intended as substitute.  Can you try it with your
attached-environment (which makes sense!)  approach ?

Best,
Martin

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: S3 method dispatch for methods in local environments

Wolfgang Viechtbauer-2
Indeed, that works:

myfun <- function(y) {
   out <- list(y=y)
   class(out) <- "myclass"
   return(out)
}

myenv <- new.env()
myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), new.env(myenv))
.S3method("print", "myclass", myenv$print.myclass)
attach(myenv)
myfun(1:4)

# [1] "1.00000" "2.00000" "3.00000" "4.00000"

Thanks for the tip!

Best,
Wolfgang

>-----Original Message-----
>From: Martin Maechler [mailto:[hidden email]]
>Sent: Tuesday, 12 May, 2020 21:05
>To: Viechtbauer, Wolfgang (SP)
>Cc: r-devel ([hidden email])
>Subject: Re: [Rd] S3 method dispatch for methods in local environments
>
>>>>>> Viechtbauer, Wolfgang (SP)
>>>>>>     on Tue, 12 May 2020 18:05:32 +0000 writes:
>
>    > Dear All,
>    > In R 3.6.3 (and earlier), method dispatch used to work for methods
>stored in local environments that are attached to the search path. For
>example:
>
>    > myfun <- function(y) {
>    > out <- list(y=y)
>    > class(out) <- "myclass"
>    > return(out)
>    > }
>
>    > print.myclass <- function(x, ...) print(formatC(x$y, format="f",
>digits=5))
>
>    > myfun(1:4)
>
>    > # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>
>    > rm(print.myclass)
>    > myenv <- new.env()
>    > myenv$print.myclass <- local(function(x, ...) print(formatC(x$y,
>format="f", digits=5)), myenv)
>    > attach(myenv)
>    > myfun(1:4)
>
>    > # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>
>    > But since R 4.0.0, this no longer words and the above prints:
>
>    > $y
>    > [1] 1 2 3 4
>
>    > attr(,"class")
>    > [1] "myclass"
>
>    > Is this intended?
>
>yes, most probably, unless
>
>    > And is there a way to still make this work?
>
>Using  the new
>
>       .S3method(<generic>, <class>, <method_function>)
>
>had been intended as substitute.  Can you try it with your
>attached-environment (which makes sense!)  approach ?
>
>Best,
>Martin

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: S3 method dispatch for methods in local environments

Sebastian Meyer-4
In reply to this post by Wolfgang Viechtbauer-2
Dear Wolfgang,

I think this new behaviour is related to the following R 4.0.0 NEWS item:

> S3 method lookup now by default skips the elements of the search path between the global and base environments.

Your environment "myenv" is attached at position 2 of the search() path
and thus now skipped in S3 method lookup.

I have just noticed that

attr(methods(class="myclass"), "info")
getS3method("print", "myclass")

both still find your function in myenv although the generic's
UseMethod() won't. I find this a bit confusing.

A solution to make R >= 4.0.0 find your method is to register the S3
method using the new function .S3method (intended for R scripts, not
packages). After running

.S3method("print", "myclass", myenv$print.myclass)

your method will be found from the generic.

Best regards,

        Sebastian


Am 12.05.20 um 20:05 schrieb Viechtbauer, Wolfgang (SP):

> Dear All,
>
> In R 3.6.3 (and earlier), method dispatch used to work for methods stored in local environments that are attached to the search path. For example:
>
> myfun <- function(y) {
>    out <- list(y=y)
>    class(out) <- "myclass"
>    return(out)
> }
>
> print.myclass <- function(x, ...) print(formatC(x$y, format="f", digits=5))
>
> myfun(1:4)
>
> # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>
> rm(print.myclass)
> myenv <- new.env()
> myenv$print.myclass <- local(function(x, ...) print(formatC(x$y, format="f", digits=5)), myenv)
> attach(myenv)
> myfun(1:4)
>
> # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>
> But since R 4.0.0, this no longer words and the above prints:
>
> $y
> [1] 1 2 3 4
>
> attr(,"class")
> [1] "myclass"
>
> Is this intended? And is there a way to still make this work?
>
> Best,
> Wolfgang
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: S3 method dispatch for methods in local environments

Wolfgang Viechtbauer-2
Thanks, Sebastian, for the pointer to the NEWS item. After some further search, I also found this in the R Blog:

https://developer.r-project.org/Blog/public/2019/08/19/s3-method-lookup/

Best,
Wolfgang

>-----Original Message-----
>From: R-devel [mailto:[hidden email]] On Behalf Of Sebastian
>Meyer
>Sent: Tuesday, 12 May, 2020 21:17
>To: [hidden email]
>Subject: Re: [Rd] S3 method dispatch for methods in local environments
>
>Dear Wolfgang,
>
>I think this new behaviour is related to the following R 4.0.0 NEWS item:
>
>> S3 method lookup now by default skips the elements of the search path
>between the global and base environments.
>
>Your environment "myenv" is attached at position 2 of the search() path
>and thus now skipped in S3 method lookup.
>
>I have just noticed that
>
>attr(methods(class="myclass"), "info")
>getS3method("print", "myclass")
>
>both still find your function in myenv although the generic's
>UseMethod() won't. I find this a bit confusing.
>
>A solution to make R >= 4.0.0 find your method is to register the S3
>method using the new function .S3method (intended for R scripts, not
>packages). After running
>
>.S3method("print", "myclass", myenv$print.myclass)
>
>your method will be found from the generic.
>
>Best regards,
>
> Sebastian
>
>
>Am 12.05.20 um 20:05 schrieb Viechtbauer, Wolfgang (SP):
>> Dear All,
>>
>> In R 3.6.3 (and earlier), method dispatch used to work for methods stored
>in local environments that are attached to the search path. For example:
>>
>> myfun <- function(y) {
>>    out <- list(y=y)
>>    class(out) <- "myclass"
>>    return(out)
>> }
>>
>> print.myclass <- function(x, ...) print(formatC(x$y, format="f",
>digits=5))
>>
>> myfun(1:4)
>>
>> # prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>>
>> rm(print.myclass)
>> myenv <- new.env()
>> myenv$print.myclass <- local(function(x, ...) print(formatC(x$y,
>format="f", digits=5)), myenv)
>> attach(myenv)
>> myfun(1:4)
>>
>> # still prints: [1] "1.00000" "2.00000" "3.00000" "4.00000"
>>
>> But since R 4.0.0, this no longer words and the above prints:
>>
>> $y
>> [1] 1 2 3 4
>>
>> attr(,"class")
>> [1] "myclass"
>>
>> Is this intended? And is there a way to still make this work?
>>
>> Best,
>> Wolfgang

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel