[R] What purpose is served by reflexive function assignments?

andrewH ahoerner at rprogress.org
Mon Dec 30 05:18:02 CET 2013


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.



More information about the R-help mailing list