Abs Spurdle
2018-Oct-15 00:19 UTC
[Rd] sys.call() inside replacement functions incorrectly returns *tmp*
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
Emil Bode
2018-Oct-15 09:57 UTC
[Rd] sys.call() inside replacement functions incorrectly returns *tmp*
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 emil.bode at dans.knaw.nl DANS: Netherlands Institute for Permanent Access to Digital Research Resources Anna van Saksenlaan 51 | 2593 HW Den Haag | +31 70 349 44 50 | info at dans.knaw.nl <mailto:info at dans.kn> | 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" <r-devel-bounces at r-project.org on behalf of spurdle.a at gmail.com> 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 ______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Duncan Murdoch
2018-Oct-15 16:01 UTC
[Rd] sys.call() inside replacement functions incorrectly returns *tmp*
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 > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >
Abs Spurdle
2018-Oct-15 23:02 UTC
[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]]
Barry Rowlingson
2018-Oct-16 08:57 UTC
[Rd] sys.call() inside replacement functions incorrectly returns *tmp*
On Tue, Oct 16, 2018 at 12:03 AM Abs Spurdle <spurdle.a at gmail.com> 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
Possibly Parallel Threads
- sys.call() inside replacement functions incorrectly returns *tmp*
- sys.call() inside replacement functions incorrectly returns *tmp*
- sys.call() inside replacement functions incorrectly returns *tmp*
- oddity in transform
- Bug when calling system/system2 (and request for Bugzilla account)