0

Hi ran the following lines and was a bit surprised. Confusion inline:

Ok so I create a list:

> x<-list()

assign 1 to be an element indexed by "a"

> x$a<-1

I ask to see what is in x

> x
$a
[1] 1

yup so far so good

next I declare a function that will take list that is passed to it and like the assignment to index "a" I'll just assign to index "b" value 2

> foo<-function(xx) {
+   xx["b"]<-2
+   print(xx)
+ }

I call the function with x - I like what I see Now my thinking is that the list object got passed (by reference as in C when you do &x) and it was destructively modified

> foo(x)
$a
[1] 1

$b
[1] 2

Now outside the body of the function I print x -- but surprised not to see b

> x
$a
[1] 1

> 

I read scooping and parameter passing docs but couldn't figure this out. Is the list being deep or shallow copied before the function body is invoked?

user975917
  • 305
  • 3
  • 13
  • 2
    You need to either `assign` or `x <- foo(x)` – akrun Jul 22 '16 at 07:23
  • so you're saying I would need to return the modified list and re-assign it. The would not be an elegant solution because I'm writing a graph walker ... let me look at assign. Thanks again – user975917 Jul 22 '16 at 07:26
  • 2
    `Now my thinking is that the list object got passed (by reference as in C)`. First time I heard C passes by reference. BTW, R is a *functional* programming language. Arguments of a function are copied and their modifications are not kept outside the function scope. – nicola Jul 22 '16 at 07:28
  • @nicola I meant forced to pass by reference like &a – user975917 Jul 22 '16 at 07:29
  • 1
    @user975917 don't get your last comment. Arguments in C are *always* passed by value. You maybe want to say that you can pass (by value of course) a reference, but that doesn't change the fact that C doesn't pass by reference. Anyway, why did you think that R functions modify their arguments? Even this info is so wrong that I wonder where you got that belief. – nicola Jul 22 '16 at 07:33
  • @nicola you are right -- what I meant was u can pass the original object (reference) by passing (by copy) the address of the object – user975917 Jul 22 '16 at 07:35
  • @nicola -- so my question is ... say you have a large graph structure that you wish to modify say splice something in -- does that mean you I have to do a complete duplication each time? – user975917 Jul 22 '16 at 07:36
  • This is another question. If you intend to build graph structures, rely on specific packages (like `igraph`) that let you build graphs efficiently. Since you are still learning, I'd suggest you not to think about how and when R copies objects, since it might be too advanced at this stage. In your example, you can simply try `x<-foo(x)` if you want to modify `x`. – nicola Jul 22 '16 at 07:42
  • @nicola ture, actually I'm trying to use the R data structures in classical CS algorithms to find out precisely what is happening under the hood – user975917 Jul 22 '16 at 07:46
  • @nicola so for example I'd like to emulate a hash table, linked list, tree etc using R lists -- the idea is to learn – user975917 Jul 22 '16 at 07:47
  • @nicola -- anyhow I solved my actual problem using a<-foo(a) but it does not seem a very elegant solution for now -- thanks again – user975917 Jul 22 '16 at 07:49
  • 1
    I understand why you would do that, but IMO it's not necessarily worthwhile. R is used for manipulating data, not so much to develop classical software with all classical data structures. Tabular data fits well into a data.frame, that is what you would use 90% of the time. Never used a linked list in years with R. Why don't you work the other way around and learn what kind of native data structure R has and what they are used for? – asachet Jul 22 '16 at 07:53
  • `does not seem a very elegant solution` why not? Important, don't try to import other languages' logic into R. R is not intended to implement tree structures and double linked list (while actually internally any R object is a double linked list), since these are low-level programming structures. R is a high level language aimed to statistical analysis. – nicola Jul 22 '16 at 07:55
  • @nicola yes I understand that -- trying to push R to the limits -- next step is writing C code based R packages -- but trying to understand performance. I'm pretty fluent in classical R use cases melt, cast, data frames, etc. -- but trying to push my knowledge – user975917 Jul 22 '16 at 07:57
  • @antoine-sac totally understand -- trying to push the envelope to better understand R – user975917 Jul 22 '16 at 07:57
  • You seem very curious and willing to learn, so I hope you don't take what I'm about to say in the wrong way. I doubt you are "fluent in classical R", as if you were, you wouldn't have been surprised by the behaviour reported in your question. Step more on the R basics and soon you'll discover how powerful R can be, especially if you intend (as it seems) to extend it with C code. But before flying, learn to walk and run. This link http://adv-r.had.co.nz/C-interface.html#calling-c can give you a glimpse on the internal nature of R objects and it's a start to write R/C code. – nicola Jul 22 '16 at 08:13

2 Answers2

1

From [1]:

The semantics of invoking a function in R argument are call-by-value.

Which means the argument is evaluated in the calling frame and deep-copied to the functions evaluation environment. (Only exception are default parameters, also see [1] for details.)

[1] https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Argument-evaluation

snaut
  • 2,261
  • 18
  • 37
1

This question discusses R's copy-on-modify mechanism in more detail; Hadley's explanation of functions here contains an example very similar to yours (look under section 'Return Values'). The short summary is that conceptually (and for all practical purposes from a user's perspective), R always passes parameters by value. Behind the scenes, an interpreter might avoid this if it can deduce that is safe to do so, but an application programmer cannot and should not make any assumptions.

Community
  • 1
  • 1
stefan.schroedl
  • 866
  • 9
  • 19