Dear Peter-- This is a truly wonderful explanation. It makes many things clear that were completely mysterious to me. For one thing, I realize that, for functions called inside the definitions of other functions, I have been confusing function definitions with function calls -- as if the called function were also being defined. So I have seen a lot of what I was calling reflexive assignments _inside_ of function definitions, but not as a _part of_ function definitions -- rather they are a part of the calls to other, already-defined functions that just happen to take place inside of function definitions.
Let me sum up a few things I think I have learned, to make sure I am not merely hallucinating an improved understanding. 1. Outside of function definitions and calls, = and <- are pretty similar in their effect. 2. Inside of the parentheses of a function call, <- assigns the RHS to the variable on the LHS in the enclosing environment, so the value is picked up when the call is executed -- but is also a permanent change in the variable of that name in the enclosing environment. (This seems like an exception to the general no-side-effects rule, yes?) 3. Inside parentheses of a function call, = assigns the RHS to the LHS, but only in the environment of that function -- more like it was in the function body. 4. Inside the parentheses of a function definition, you can not do a <- assignment at all, and = has a a pretty different secondary meaning, a sort of conditional assignment, along the lines of "if you can not match the argument before this positionally, use the value of the RHS. 5. The names of formals in the function definition do not matter outside the function. Only their position (or an = assignment) matters. You can not get a function to recognize a variable in its surrounding environment because it has the same name as the name of a formal in the function definition. Conversely, inside the function, only the formal name matters. if f<-function(Y){X}, f(X) still gets you an "argument X is missing" error. 6. In a call, f(x=x) is different from f(x) if and only if x has a default value different from the value of x in the calling environment. 7. I have learned by experiment that a reflexive assignment with = in a function definition does not assign the value of x in the calling environment as the default, though I do not know why. In fact, I have not been able to make X=X do anything useful (and different from plain X) inside the parentheses of a function definition, unless I am trying to generate strange "recursive default error" warnings. So the simple rule i wanted with respect to function definitions is "just say no". Is that more or less right? Many thanks! --andrewH plangfelder wrote > On Sat, Dec 28, 2013 at 7:27 PM, Andrew Hoerner < > ahoerner@ > > wrote: >> Let us suppose that we have a function foo(X) which is called inside >> another function, bar(). Suppose, moreover, that the name "X" has been >> assigned a value when foo is called: >> >> X <- 2 >> bar(X=X){ >> foo(X) >> } >> >> I have noticed that many functions contain arguments with defaults of the >> form X=X. Call this reflexive assignment of arguments. > > Your example code makes little sense, it throws an error even before > reaching foo(): > >> X <- 2 >> bar(X=X){ > Error: unexpected '{' in "bar(X=X){" >> foo(X) > Error: could not find function "foo" >> } > Error: unexpected '}' in "}" > > > What you may have in mind is something like > > bar = function(X) > { > foo(X) > } > > X<-2 > bar(X=X) > > Note that bar(X=4) is different from bar(X<-4), as seen here: > > # Define a trivial function >> bar = function(X) {X+2} >> >> X = 0 >> bar(X=2) > [1] 4 > # Here only the formal argument X of function bar was set to 2; the > global variable X was left untouched: >> X > [1] 0 > # This assigns the value 4 to the global variable X and uses that > value as the value for the first formal argument of bar(): >> bar(X<-4) > [1] 6 > # Note that X changed in the global environment >> X > [1] 4 > > What you call "reflexive assignment" X=X is not really: the left hand > side is the formal argument of bar(), the right hand side is the > variable X in the calling environment of bar() (in this case global > environment). > > Oh yes, and it has absolutely nothing to do with defaults. If you use > my example above, the default for the argument X is 2, but doing > X=0 > bar(X=X) > > will call the function with argument X=0, not X=2. > > When there is only one argument, saying X=X does not make much sense, > but when there are many arguments, say > > bar = function(X=0, Y=0, Z=0) > > and you only want to set the argument Z to a value you call Z in the > calling function, saying > > bar(Z=Z) > > makes perfect sense and is very different from saying > > bar(Z) > > which would set the argument X to value Z, and leave argument Z at the > default. > > Hope this helps. > > Peter > > ______________________________________________ > R-help@ > mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. -- View this message in context: http://r.789695.n4.nabble.com/What-purpose-is-served-by-reflexive-function-assignments-tp4682794p4682825.html Sent from the R help mailing list archive at Nabble.com. ______________________________________________ R-help@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.