I was just considering trying to clean up the arguments to a function
that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this without
making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]]
[1] 1
[[2]]
[1] 2
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
Paul
====================================================================================
La version fran?aise suit le texte anglais.
------------------------------------------------------------------------------------
This email may contain privileged and/or confidential inform...{{dropped}}
foo2Args()
6 messages · Duncan Murdoch, Paul Gilbert, Gabor Grothendieck
On 6/30/2006 4:19 PM, Paul Gilbert wrote:
I was just considering trying to clean up the arguments to a function
that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this without
making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]] [1] 1 [[2]] [1] 2
I don't think it really works, it's just a coincidence that the answer matches your expectations: > foo(3) [[1]] [1] 1 [[2]] [1] 2 Or maybe I am completely misunderstanding your expectations...
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
This is a somewhat subtle thing about the way args are evaluated. What is done makes lots of sense once you understand it: - When you specify an argument in the call, the expression you give is evaluated in the current context. In the context where you made this call, foo2Args is not defined, hence the error. - When you specify a default for an argument, it is evaluated in the local context of the function evaluation. So as a default, foo2Args is recognized, because it's a local variable within foo. You also need to remember "lazy evaluation": neither of the above actually take place until args is used. R is pretty flexible, so it's probably possible to do whatever you intended here; can you describe exactly what you want to happen? Duncan Murdoch
Duncan Murdoch wrote:
On 6/30/2006 4:19 PM, Paul Gilbert wrote:
I was just considering trying to clean up the arguments to a function
that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this
without making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]] [1] 1 [[2]] [1] 2
I don't think it really works, it's just a coincidence that the answer matches your expectations:
foo(3)
[[1]] [1] 1 [[2]] [1] 2 Or maybe I am completely misunderstanding your expectations...
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
This is a somewhat subtle thing about the way args are evaluated. What is done makes lots of sense once you understand it: - When you specify an argument in the call, the expression you give is evaluated in the current context. In the context where you made this call, foo2Args is not defined, hence the error. - When you specify a default for an argument, it is evaluated in the local context of the function evaluation. So as a default, foo2Args is recognized, because it's a local variable within foo. You also need to remember "lazy evaluation": neither of the above actually take place until args is used. R is pretty flexible, so it's probably possible to do whatever you intended here; can you describe exactly what you want to happen?
I guess what I want to happen is that when args is used it it gets evaluated in the local context of the function, whether or not I am specifying the argument or using the default. Is there a way to do that? What I expected to happen was that it would always get evaluated either in the local context or in the calling context, i.e., it would fail or not fail, but that would not depend on whether I am specifying the argument or using the default, so your first points explain this. Thanks, Paul
Duncan Murdoch
====================================================================================
La version fran?aise suit le texte anglais.
------------------------------------------------------------------------------------
This email may contain privileged and/or confidential inform...{{dropped}}
On 6/30/06, Paul Gilbert <pgilbert at bank-banque-canada.ca> wrote:
Duncan Murdoch wrote:
On 6/30/2006 4:19 PM, Paul Gilbert wrote:
I was just considering trying to clean up the arguments to a function
that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this
without making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]] [1] 1 [[2]] [1] 2
I don't think it really works, it's just a coincidence that the answer matches your expectations:
foo(3)
[[1]] [1] 1 [[2]] [1] 2 Or maybe I am completely misunderstanding your expectations...
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
This is a somewhat subtle thing about the way args are evaluated. What is done makes lots of sense once you understand it: - When you specify an argument in the call, the expression you give is evaluated in the current context. In the context where you made this call, foo2Args is not defined, hence the error. - When you specify a default for an argument, it is evaluated in the local context of the function evaluation. So as a default, foo2Args is recognized, because it's a local variable within foo. You also need to remember "lazy evaluation": neither of the above actually take place until args is used. R is pretty flexible, so it's probably possible to do whatever you intended here; can you describe exactly what you want to happen?
I guess what I want to happen is that when args is used it it gets evaluated in the local context of the function, whether or not I am specifying the argument or using the default. Is there a way to do that? What I expected to happen was that it would always get evaluated either in the local context or in the calling context, i.e., it would fail or not fail, but that would not depend on whether I am specifying the argument or using the default, so your first points explain this.
I think its better that a function check its own arguments. Having the caller check the arguments by calling foo2Args seems to distribute the functionality between the function and the caller so I don't think that that is desirable.
On 6/30/2006 5:12 PM, Paul Gilbert wrote:
Duncan Murdoch wrote:
On 6/30/2006 4:19 PM, Paul Gilbert wrote:
I was just considering trying to clean up the arguments to a function
that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this
without making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]] [1] 1 [[2]] [1] 2
I don't think it really works, it's just a coincidence that the answer matches your expectations:
foo(3)
[[1]] [1] 1 [[2]] [1] 2 Or maybe I am completely misunderstanding your expectations...
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
This is a somewhat subtle thing about the way args are evaluated. What is done makes lots of sense once you understand it: - When you specify an argument in the call, the expression you give is evaluated in the current context. In the context where you made this call, foo2Args is not defined, hence the error. - When you specify a default for an argument, it is evaluated in the local context of the function evaluation. So as a default, foo2Args is recognized, because it's a local variable within foo. You also need to remember "lazy evaluation": neither of the above actually take place until args is used. R is pretty flexible, so it's probably possible to do whatever you intended here; can you describe exactly what you want to happen?
I guess what I want to happen is that when args is used it it gets evaluated in the local context of the function, whether or not I am specifying the argument or using the default. Is there a way to do that?
I think this would work:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args <- eval(substitute(args))
args
}
The explanation is this:
substitute(args) gets the expression attached to args without evaluating
it. eval( substitute(args) ) then evaluates it; since I didn't say which
environment to work in, it defaults to the current evaluation environment.
HOWEVER, this function is a bad idea. Users don't expect evaluation
like this. For example, this would mess it up:
args <- 2
foo(1, args=foo2Args(a=args, b=10))
because it would try to evaluate "args" in the local environment, rather
than where the user put it. You'd get weird behaviour if any of the
values in foo2Args used variables rather than constants, because they'd
be evaluated in the function, not in the user's workspace.
Duncan Murdoch
What I expected to happen was that it would always get evaluated either in the local context or in the calling context, i.e., it would fail or not fail, but that would not depend on whether I am specifying the argument or using the default, so your first points explain this. Thanks, Paul
Duncan Murdoch
====================================================================================
La version fran?aise suit le texte anglais.
------------------------------------------------------------------------------------
This email may contain privileged and/or confidential inform...{{dropped}}
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Duncan Murdoch wrote:
On 6/30/2006 5:12 PM, Paul Gilbert wrote:
Duncan Murdoch wrote:
On 6/30/2006 4:19 PM, Paul Gilbert wrote:
I was just considering trying to clean up the arguments to a
function that calls other functions,
and was playin with a suggestion Achim made during a conversation at
useR. The idea is, instead of using list(), use a small function to
construct and check arguments. My hope was to be able to do this
without making it globally visible:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args
}
Now,
> foo(1) # should I be surprized that this works
[[1]] [1] 1 [[2]] [1] 2
I don't think it really works, it's just a coincidence that the answer matches your expectations:
foo(3)
[[1]] [1] 1 [[2]] [1] 2 Or maybe I am completely misunderstanding your expectations...
> foo(1, args=foo2Args(a=2, b=10)) # or that this does not
Error in foo(1, args = foo2Args(a = 2, b = 10)) :
could not find function "foo2Args"
This is a somewhat subtle thing about the way args are evaluated. What is done makes lots of sense once you understand it: - When you specify an argument in the call, the expression you give is evaluated in the current context. In the context where you made this call, foo2Args is not defined, hence the error. - When you specify a default for an argument, it is evaluated in the local context of the function evaluation. So as a default, foo2Args is recognized, because it's a local variable within foo. You also need to remember "lazy evaluation": neither of the above actually take place until args is used. R is pretty flexible, so it's probably possible to do whatever you intended here; can you describe exactly what you want to happen?
I guess what I want to happen is that when args is used it it gets evaluated in the local context of the function, whether or not I am specifying the argument or using the default. Is there a way to do that?
I think this would work:
foo <- function(x, args=foo2Args()) {
foo2Args <- function(a=1, b=2){list(a,b)}
# above would actual do more testing of args
#now I would call foo2 with args, but to test just
args <- eval(substitute(args))
args
}
The explanation is this:
substitute(args) gets the expression attached to args without evaluating
it. eval( substitute(args) ) then evaluates it; since I didn't say which
environment to work in, it defaults to the current evaluation environment.
HOWEVER, this function is a bad idea. Users don't expect evaluation
like this. For example, this would mess it up:
args <- 2
foo(1, args=foo2Args(a=args, b=10))
because it would try to evaluate "args" in the local environment, rather
than where the user put it. You'd get weird behaviour if any of the
values in foo2Args used variables rather than constants, because they'd
be evaluated in the function, not in the user's workspace.
Yes, I realized on the way home that what I want is not what I said, because I need the function to be found (thus in the local context) but I need the arguments to foo2Args from the calling context, if they are supplied. The general idea is to provide a nice clean way to pass arguments along to other functions. If foo is calling a few functions this becomes really messy, and even moreso if those functions call other functions that need arguments passed along. The way I have always done this is with a list, but there may be some advantage to using a function that constructs the argument. However, there are likely to be namespace conflicts if everyone does this and this constructing function name has to be exported, or even visible outside of the call to the function. For example, one of the function I want to call is optim. If everyone that calls optim wants to do this (supposing it is a good idea), they would all probably decide a good name for the function is optimArgs. Perhaps sticking with a list is the best idea. Thanks, Paul
Duncan Murdoch
What I expected to happen was that it would always get evaluated either in the local context or in the calling context, i.e., it would fail or not fail, but that would not depend on whether I am specifying the argument or using the default, so your first points explain this. Thanks, Paul
Duncan Murdoch
====================================================================================
La version fran?aise suit le texte anglais.
------------------------------------------------------------------------------------
This email may contain privileged and/or confidential inform...{{dropped}}