sys.call() inside replacement functions incorrectly returns *tmp*

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

sys.call() inside replacement functions incorrectly returns *tmp*

Abs Spurdle
Kia Ora

Let's say we have:
"myreplacementfunction<-" = function (..., value)
{ call = sys.call ()
        print (as.list (call) )
        0
}

Then we call:
x = 0
myreplacementfunction (x, y, z) = 0

It will return:
[[1]]
`myreplacementfunction<-`

[[2]]
`*tmp*`

[[3]]
y

[[4]]
z

$value
<promise: 0x06fb6968>

There's two problems here.
Firstly, x has to be defined otherwise we get an error message.
Secondly, the first argument is returned as *tmp*.

Both are incorrect.

It should be possible to call the function without defining x.
And it should return x rather than *tmp*.
In other words, replacement function calls should be the same as other
function calls.

Although it gets y and z right.


kind regards
Abs

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

Re: sys.call() inside replacement functions incorrectly returns *tmp*

Emil
Hi,

Agreed that it would be better if sys.call() were to return "x" instead of "*tmp*", as it behaves as a local variable. Although I'm not sure what problem it would solve, the effect here is comparable to what happens when calling a function indirectly (although then you could use sys.call(2), which here doesn't work).
 
But your other suggestion, accepting non-existent x without error, would cause a lot of other problems I think. The way I see it, replacement functions are meant to edit a certain aspect of an object/variable. Which only makes sense if it exists in the first place. With your replacement function there may be a use for setting new values but what should e.g. "levels(x) <- letters" do? Make a new empty factor? Discard any results? Make an as-empty-as-possible variable (probably an empty list) with a levels attribute? I think the current behaviour is fine.
In general, I can't see any scenario where you want to "edit" a variable, but make the end-result independent of the original value (Then you'd simply assign, without a custom function). So any replacement function is going to read the original value of x, so is there any downside to requiring it?

Also, I have to say that your example looks confusing to me. Do you want to assign 0 to x, and ignore all other arguments? Or was it your intention to set all variables to 0? And having an ellipsis argument only makes sense in my experience if these arguments are optional. Which would mean myreplacementfunction() = 0 should be a valid call, but I can't see what that would be expected to do. So I would at least make the call `myreplacementfunction(x, ..., value).
The reason y and z are "right" is because these are simple extra input parameters, which can have any value, including missing, they needn't be evaluated.

Best regards,
Emil Bode
 
Data-analyst
 
+31 6 43 83 89 33
[hidden email]
 
DANS: Netherlands Institute for Permanent Access to Digital Research Resources
Anna van Saksenlaan 51 | 2593 HW Den Haag | +31 70 349 44 50 | [hidden email] <mailto:[hidden email]> | dans.knaw.nl <applewebdata://71F677F0-6872-45F3-A6C4-4972BF87185B/www.dans.knaw.nl>
DANS is an institute of the Dutch Academy KNAW <http://knaw.nl/nl> and funding organisation NWO <http://www.nwo.nl/>.

On 15/10/2018, 02:20, "R-devel on behalf of Abs Spurdle" <[hidden email] on behalf of [hidden email]> wrote:

    Kia Ora
   
    Let's say we have:
    "myreplacementfunction<-" = function (..., value)
    { call = sys.call ()
    print (as.list (call) )
    0
    }
   
    Then we call:
    x = 0
    myreplacementfunction (x, y, z) = 0
   
    It will return:
    [[1]]
    `myreplacementfunction<-`
   
    [[2]]
    `*tmp*`
   
    [[3]]
    y
   
    [[4]]
    z
   
    $value
    <promise: 0x06fb6968>
   
    There's two problems here.
    Firstly, x has to be defined otherwise we get an error message.
    Secondly, the first argument is returned as *tmp*.
   
    Both are incorrect.
   
    It should be possible to call the function without defining x.
    And it should return x rather than *tmp*.
    In other words, replacement function calls should be the same as other
    function calls.
   
    Although it gets y and z right.
   
   
    kind regards
    Abs
   
    ______________________________________________
    [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: sys.call() inside replacement functions incorrectly returns *tmp*

Duncan Murdoch-2
In reply to this post by Abs Spurdle
On 14/10/2018 8:19 PM, Abs Spurdle wrote:

> Kia Ora
>
> Let's say we have:
> "myreplacementfunction<-" = function (..., value)
> { call = sys.call ()
> print (as.list (call) )
> 0
> }
>
> Then we call:
> x = 0
> myreplacementfunction (x, y, z) = 0
>
> It will return:
> [[1]]
> `myreplacementfunction<-`
>
> [[2]]
> `*tmp*`
>
> [[3]]
> y
>
> [[4]]
> z
>
> $value
> <promise: 0x06fb6968>
>
> There's two problems here.
> Firstly, x has to be defined otherwise we get an error message.
> Secondly, the first argument is returned as *tmp*.
>
> Both are incorrect.

Both of these are documented (by example) in the R Language Definition
manual, section 3.4.4:

"Assignment to subsets of a structure is a special case of a general
mechanism for complex assignment:

x[3:5] <- 13:15
The result of this command is as if the following had been executed

`*tmp*` <- x
x <- "[<-"(`*tmp*`, 3:5, value=13:15)
rm(`*tmp*`)"

Duncan Murdoch

>
> It should be possible to call the function without defining x.
> And it should return x rather than *tmp*.
> In other words, replacement function calls should be the same as other
> function calls.
>
> Although it gets y and z right.
>
>
> kind regards
> Abs
>
> ______________________________________________
> [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: sys.call() inside replacement functions incorrectly returns *tmp*

Abs Spurdle
In reply to this post by Emil
Kia Ora

> Although I'm not sure what problem it would solve...

Given that you asked, I was interested in writing a multiple assignment
function as a replacement function, so something like:
massign (x, y, z) = construct.some list ()

Obviously, that's not possible.

Probably the best example I can think of is converting cartesian
coordinates to polar coordinates.
Then we might have something like (note, untested, written in my email):
cart2polar = function (x, y)
    list (theta=atan (y / x), r=sqrt (x * x + y * y) )

massign (r, theta) = cart2polar (x, y)

Now, I'm considering a multiple assignment operator, so something like:
c (theta, r) $<-$ cart2polar (x, y)

And while we're on the topic, I'm also considering an attribute operator
(to access object attributes), something like:
myobject%$%myattribute

This would be similar to . in C++/Java or @ in S4.
And seems like something obvious that's missing from R.

Implementing an attribute read this way is easy, however, implementing an
attribute assignment this way (without language level support) is difficult.


kind regards
Abs

        [[alternative HTML version deleted]]

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

Re: sys.call() inside replacement functions incorrectly returns *tmp*

Gábor Csárdi
Seems like there are at least two packages for multiple assignment,
maybe one of them solves your needs, zeallot and dub.

https://r-pkg.org/search.html?q=multiple+assignment

Gabor
On Tue, Oct 16, 2018 at 12:03 AM Abs Spurdle <[hidden email]> wrote:

>
> Kia Ora
>
> > Although I'm not sure what problem it would solve...
>
> Given that you asked, I was interested in writing a multiple assignment
> function as a replacement function, so something like:
> massign (x, y, z) = construct.some list ()
>
> Obviously, that's not possible.
>
> Probably the best example I can think of is converting cartesian
> coordinates to polar coordinates.
> Then we might have something like (note, untested, written in my email):
> cart2polar = function (x, y)
>     list (theta=atan (y / x), r=sqrt (x * x + y * y) )
>
> massign (r, theta) = cart2polar (x, y)
>
> Now, I'm considering a multiple assignment operator, so something like:
> c (theta, r) $<-$ cart2polar (x, y)
>
> And while we're on the topic, I'm also considering an attribute operator
> (to access object attributes), something like:
> myobject%$%myattribute
>
> This would be similar to . in C++/Java or @ in S4.
> And seems like something obvious that's missing from R.
>
> Implementing an attribute read this way is easy, however, implementing an
> attribute assignment this way (without language level support) is difficult.
>
>
> kind regards
> Abs
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> [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: sys.call() inside replacement functions incorrectly returns *tmp*

barry rowlingson
In reply to this post by Emil
On Tue, Oct 16, 2018 at 12:03 AM Abs Spurdle <[hidden email]> wrote:

> Probably the best example I can think of is converting cartesian
> coordinates to polar coordinates.
> Then we might have something like (note, untested, written in my email):
> cart2polar = function (x, y)
>     list (theta=atan (y / x), r=sqrt (x * x + y * y) )
>
> massign (r, theta) = cart2polar (x, y)
>
> Now, I'm considering a multiple assignment operator, so something like:
> c (theta, r) $<-$ cart2polar (x, y)

This is something that comes up occasionally and as noted by Gabor,
has been implemented in packages.

But I am not keen on unpacking the return from a function into
multiple objects. The reason your `cart2polar` function returns a list
of theta and r is because it is returning a polar coordinate, and that
coordinate needs both. Why unpack them? If you don't need theta, then
do `r = cart2polar(x,y)$r`. If you need theta and r, then keep them
together in a single object. If you need to call a function  that
needs separate theta and r, use `plot(d$r, d$theta)`. Its a bit more
typing but that's a false efficiency when you want code to be tidy and
well-structured, and to convey meaning. `plot(this$r, this$theta)` is
clearly a plot of something to do with `this`, and you can see that
the r and the theta are coming from the same thing, whereas a
`(r,theta) %=% foo(x,y)` some place and then `plot(r, theta)`
somewhere else has broken the connection.

Barry

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

Re: sys.call() inside replacement functions incorrectly returns *tmp*

Emil
In reply to this post by Abs Spurdle
Well,

I think what you want to do is hard if you insist on using a replacement function, i.e. massign(vars) <- values.
But as you wrote, you can use a modified assignment operator, or you could write something comparable to assign, so massign(listofvars, listofvalues, environment) shouldn’t be too hard.
I believe in this context, the term “replacement function” is a bit confusing. In my experience, replacement functions are for editing a certain aspect of a variable or object, mostly attributes, or they can replace certain elements. But in order to edit something, it has to exist in the first place.
It may be that I’m reading it wrong, but to me “massign (x, y, z) = somelist” reads “I want to edit some aspects of x, y and z, by inputting somelist to them”. In that guise, I can see some function like mlevels(factor1, factor2, factor3) <- as.character(1:10), to set the level attributes to all three factors to the same set of levels.
That’s not something easily supported with replacement functions, but it is possible.
But for creating new objects, or reassigning them, a replacement function seems not the way to go to me.
And as Barry noted, why do you want to pull these values apart in the first place? I guess your example of polar coordinates was just an example, but if you want to store multiple values that’s a lot easier in a list, and it keeps your workspace tidier.
For your other point, editing attributes is possible with `attr<-`.
If you want to have it as an infix operator without having to use quotes:
`%$%<-` <- function(obj, attr, value) {
  `attr<-`(obj, as.character(substitute(attr)), value)
}
Now “myobj %$% myattr <- values “ will do as you desire

Best regards,
Emil Bode

From: Abs Spurdle <[hidden email]>
Date: Tuesday, 16 October 2018 at 01:02
To: Emil Bode <[hidden email]>
Cc: r-devel <[hidden email]>
Subject: Re: [Rd] sys.call() inside replacement functions incorrectly returns *tmp*

Kia Ora

> Although I'm not sure what problem it would solve...

Given that you asked, I was interested in writing a multiple assignment function as a replacement function, so something like:
massign (x, y, z) = construct.some list ()

Obviously, that's not possible.

Probably the best example I can think of is converting cartesian coordinates to polar coordinates.
Then we might have something like (note, untested, written in my email):
cart2polar = function (x, y)
    list (theta=atan (y / x), r=sqrt (x * x + y * y) )

massign (r, theta) = cart2polar (x, y)

Now, I'm considering a multiple assignment operator, so something like:
c (theta, r) $<-$ cart2polar (x, y)

And while we're on the topic, I'm also considering an attribute operator (to access object attributes), something like:
myobject%$%myattribute

This would be similar to . in C++/Java or @ in S4.
And seems like something obvious that's missing from R.

Implementing an attribute read this way is easy, however, implementing an attribute assignment this way (without language level support) is difficult.


kind regards
Abs


        [[alternative HTML version deleted]]

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