parent.frame(1) of a S4 method is not a calling environment.

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

parent.frame(1) of a S4 method is not a calling environment.

Vitalie S.-2

Dear Developers,

I wonder what are the parent.frame rules for methods. For ordinary functions one
can call parent.frame() and be sure that it is the environment of a calling
function. With S4 aparently it is not the case.

Here is what I have discovered by trial and error so far:

> setClass("A", contains="vector")
[1] "A"
> setGeneric("foo", def=function(a, ...){standardGeneric("foo")})
[1] "foo"
>
> setMethod("foo", signature("A"),
+           def=function(a, ...){
+             cat("--pf1--\n")
+             ls(parent.frame(1))
+             ## cat("--pf2--")
+             ## ls(parent.frame(2))
+           })
[1] "foo"
>
> tf <- function(){
+   b <- 4
+   foo(new("A")) #ok
+ }
>
> tf() #ok
--pf1--
[1] "b"

The above works like predicted.
Now, a small change. The "b" argument which is not in the signature, but has a
role of an additional parameter to the function:

> setMethod("foo", signature("A"),
+           def=function(a, b, ...){
+             cat("--pf1--\n")
+             print(ls(parent.frame(1)))
+             cat("--pf2--\n")
+             print(ls(parent.frame(2)))
+           })
[1] "foo"
>
> tf()  #oups
--pf1--
[1] "a"
--pf2--
[1] "b"
>

So,  can I be sure that for such functions parent.frame(2) will always work?
What are the additional rules?

Many thanks,
Vitaly.

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

Re: parent.frame(1) of a S4 method is not a calling environment.

Martin Morgan
On 08/15/2010 02:39 PM, Vitaly S. wrote:

>
> Dear Developers,
>
> I wonder what are the parent.frame rules for methods. For ordinary functions one
> can call parent.frame() and be sure that it is the environment of a calling
> function. With S4 aparently it is not the case.
>
> Here is what I have discovered by trial and error so far:
>
>> setClass("A", contains="vector")
> [1] "A"
>> setGeneric("foo", def=function(a, ...){standardGeneric("foo")})
> [1] "foo"
>>
>> setMethod("foo", signature("A"),
> +           def=function(a, ...){
> +             cat("--pf1--\n")
> +             ls(parent.frame(1))
> +             ## cat("--pf2--")
> +             ## ls(parent.frame(2))
> +           })
> [1] "foo"
>>
>> tf <- function(){
> +   b <- 4
> +   foo(new("A")) #ok
> + }
>>
>> tf() #ok
> --pf1--
> [1] "b"
>
> The above works like predicted.
> Now, a small change. The "b" argument which is not in the signature, but has a
> role of an additional parameter to the function:
>
>> setMethod("foo", signature("A"),
> +           def=function(a, b, ...){
> +             cat("--pf1--\n")
> +             print(ls(parent.frame(1)))
> +             cat("--pf2--\n")
> +             print(ls(parent.frame(2)))
> +           })
> [1] "foo"
>>
>> tf()  #oups
> --pf1--
> [1] "a"
> --pf2--
> [1] "b"
>>
>
> So,  can I be sure that for such functions parent.frame(2) will always work?
> What are the additional rules?

callNextMethod() will cause additional problems; the idea that you'll
grab things from somewhere other than function arguments doesn't seem
like a robust design, even if it's used in some important parts of R.

Martin

>
> Many thanks,
> Vitaly.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel


--
Martin Morgan
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109

Location: Arnold Building M1 B861
Phone: (206) 667-2793

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

Re: parent.frame(1) of a S4 method is not a calling environment.

Vitalie S.-2

Martin Morgan <[hidden email]> writes:

>>
>> So,  can I be sure that for such functions parent.frame(2) will always work?
>> What are the additional rules?
>
> callNextMethod() will cause additional problems; the idea that you'll
> grab things from somewhere other than function arguments doesn't seem
> like a robust design, even if it's used in some important parts of R.
>
> Martin
>

That make it difficult to handle unevaluated expressions in methods. A solution
would be to explicitly require the users to use quote() or expression(),  and
then to use the "expression" in the signature. Slightly unpleasant, though.

Standardised, simpler syntax like .() in  ggplot and plyr,  would be handy here.
Hopefully .() is not grabbed for something else in meanwhile:).

Vitaly.

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

Re: parent.frame(1) of a S4 method is not a calling environment.

Duncan Murdoch-2
Vitaly S. wrote:

> Martin Morgan <[hidden email]> writes:
>  
>>> So,  can I be sure that for such functions parent.frame(2) will always work?
>>> What are the additional rules?
>>>      
>> callNextMethod() will cause additional problems; the idea that you'll
>> grab things from somewhere other than function arguments doesn't seem
>> like a robust design, even if it's used in some important parts of R.
>>
>> Martin
>>
>>    
>
> That make it difficult to handle unevaluated expressions in methods. A solution
> would be to explicitly require the users to use quote() or expression(),  and
> then to use the "expression" in the signature. Slightly unpleasant, though.
>
>  

You could use formulas for that.  If you pass in

formula = ~ x + y*z

then environment(formula) will be the right evaluation environment, and
formula[[2]] will be the unevaluated x + y*z.

Duncan Murdoch

> Standardised, simpler syntax like .() in  ggplot and plyr,  would be handy here.
> Hopefully .() is not grabbed for something else in meanwhile:).
>
> Vitaly.
>
> ______________________________________________
> [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: parent.frame(1) of a S4 method is not a calling environment.

Vitalie S.-2
Duncan Murdoch <[hidden email]> writes:

> Vitaly S. wrote:
>> Martin Morgan <[hidden email]> writes:
>>  
>>>> So,  can I be sure that for such functions parent.frame(2) will always work?
>>>> What are the additional rules?
>>>>      
>>> callNextMethod() will cause additional problems; the idea that you'll
>>> grab things from somewhere other than function arguments doesn't seem
>>> like a robust design, even if it's used in some important parts of R.
>>>
>>> Martin
>>>
>>>    
>>
>> That make it difficult to handle unevaluated expressions in methods. A solution
>> would be to explicitly require the users to use quote() or expression(),  and
>> then to use the "expression" in the signature. Slightly unpleasant, though.
>>
>>  
>
> You could use formulas for that.  If you pass in
>
> formula = ~ x + y*z
>
> then environment(formula) will be the right evaluation environment, and formula[[2]] will be the unevaluated x +
> y*z.
>
> Duncan Murdoch

Thank you Duncan, I didn't know that.

For programmatic use though, formula interface is slightly inconvenient. A
specialized function and class would be desirable. With the advent of more and
more complex S4 classes, unevaluated expressions in methods calls will became a
necessity, that's my feeling.

Thank you.
Vitaly.

>
>> Standardised, simpler syntax like .() in  ggplot and plyr,  would be handy here.
>> Hopefully .() is not grabbed for something else in meanwhile:).
>>
>> Vitaly.
>>
>> ______________________________________________
>> [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: parent.frame(1) of a S4 method is not a calling environment.

Hadley Wickham-2
On Tuesday, August 17, 2010, Vitaly S. <[hidden email]> wrote:

> Duncan Murdoch <[hidden email]> writes:
>
>> Vitaly S. wrote:
>>> Martin Morgan <[hidden email]> writes:
>>>
>>>>> So,  can I be sure that for such functions parent.frame(2) will always work?
>>>>> What are the additional rules?
>>>>>
>>>> callNextMethod() will cause additional problems; the idea that you'll
>>>> grab things from somewhere other than function arguments doesn't seem
>>>> like a robust design, even if it's used in some important parts of R.
>>>>
>>>> Martin
>>>>
>>>>
>>>
>>> That make it difficult to handle unevaluated expressions in methods. A solution
>>> would be to explicitly require the users to use quote() or expression(),  and
>>> then to use the "expression" in the signature. Slightly unpleasant, though.
>>>
>>>
>>
>> You could use formulas for that.  If you pass in
>>
>> formula = ~ x + y*z
>>
>> then environment(formula) will be the right evaluation environment, and formula[[2]] will be the unevaluated x +
>> y*z.
>>
>> Duncan Murdoch
>
> Thank you Duncan, I didn't know that.
>
> For programmatic use though, formula interface is slightly inconvenient. A
> specialized function and class would be desirable. With the advent of more and
> more complex S4 classes, unevaluated expressions in methods calls will became a
> necessity, that's my feeling.

I probably should move the quoting related out of plyr into it's own
package to facilitate this type of reuse. I think the current
structure is quite general.

Hadley

--
Assistant Professor / Dobelman Family Junior Chair
Department of Statistics / Rice University
http://had.co.nz/

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

Re: parent.frame(1) of a S4 method is not a calling environment.

Vitalie S.-2
Hadley Wickham <[hidden email]> writes:

> On Tuesday, August 17, 2010, Vitaly S. <[hidden email]> wrote:
>> Duncan Murdoch <[hidden email]> writes:
>>
>>> Vitaly S. wrote:
>>>> Martin Morgan <[hidden email]> writes:
>>>>
>>>>>> So,  can I be sure that for such functions parent.frame(2) will always work?
>>>>>> What are the additional rules?
>>>>>>
>>>>> callNextMethod() will cause additional problems; the idea that you'll
>>>>> grab things from somewhere other than function arguments doesn't seem
>>>>> like a robust design, even if it's used in some important parts of R.
>>>>>
>>>>> Martin
>>>>>
>>>>>
>>>>
>>>> That make it difficult to handle unevaluated expressions in methods. A solution
>>>> would be to explicitly require the users to use quote() or expression(),  and
>>>> then to use the "expression" in the signature. Slightly unpleasant, though.
>>>>
>>>>
>>>
>>> You could use formulas for that.  If you pass in
>>>
>>> formula = ~ x + y*z
>>>
>>> then environment(formula) will be the right evaluation environment, and formula[[2]] will be the unevaluated x +
>>> y*z.
>>>
>>> Duncan Murdoch
>>
>> Thank you Duncan, I didn't know that.
>>
>> For programmatic use though, formula interface is slightly inconvenient. A
>> specialized function and class would be desirable. With the advent of more and
>> more complex S4 classes, unevaluated expressions in methods calls will became a
>> necessity, that's my feeling.
>
> I probably should move the quoting related out of plyr into it's own
> package to facilitate this type of reuse. I think the current
> structure is quite general.

That would be neat. An S4 class "quote" which would store the parent.frame as a
slot would be great!

>
> Hadley

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