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
Reasonably Related 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)