An embedded and charset-unspecified text was scrubbed... Name: not available URL: <https://stat.ethz.ch/pipermail/r-devel/attachments/20130717/99436f19/attachment.pl>
On the mechanics of function evaluation and argument matching
6 messages · Brian Lee Yung Rowe, R. Michael Weylandt, Ben Bolker +1 more
On Wed, Jul 17, 2013 at 9:58 AM, Brian Rowe <rowe at muxspace.com> wrote:
Hello, Section 4.3.2 of the R language definition [1] states that argument matching to formal arguments is a 3-pass process to match arguments to a function. An error is generated if any (supplied) arguments are left unmatched. Interestingly the opposite is not true as any unmatched formals does not generate an error.
f <- function(x,y,z) x f(2)
[1] 2
f(2,3)
[1] 2 Since R is lazily evaluated, I understand that it is not an error for an unused argument to be unassigned. However, it is surprising to me that a function need not be called with all its required arguments. I guess in this situation technically "required arguments" means required and referenced arguments.
f()
Error in f() : argument "x" is missing, with no default Can anyone shed light on the reasoning for this design choice?
I'm not sure I can, but I'd look around at how the missing() function is used. Cheers, MW
Thanks for the lead. Given the example in ?missing though, wouldn't it be safer to explicitly define a default value of NULL:
myplot <- function(x, y=NULL) {
if(is.null(y)) {
y <- x
x <- 1:length(y)
}
plot(x, y)
}
On Jul 17, 2013, at 11:05 AM, "R. Michael Weylandt" <michael.weylandt at gmail.com> wrote:
On Wed, Jul 17, 2013 at 9:58 AM, Brian Rowe <rowe at muxspace.com> wrote:
Hello, Section 4.3.2 of the R language definition [1] states that argument matching to formal arguments is a 3-pass process to match arguments to a function. An error is generated if any (supplied) arguments are left unmatched. Interestingly the opposite is not true as any unmatched formals does not generate an error.
f <- function(x,y,z) x f(2)
[1] 2
f(2,3)
[1] 2 Since R is lazily evaluated, I understand that it is not an error for an unused argument to be unassigned. However, it is surprising to me that a function need not be called with all its required arguments. I guess in this situation technically "required arguments" means required and referenced arguments.
f()
Error in f() : argument "x" is missing, with no default Can anyone shed light on the reasoning for this design choice?
I'm not sure I can, but I'd look around at how the missing() function is used. Cheers, MW
Brian Rowe <rowe <at> muxspace.com> writes:
Thanks for the lead. Given the example in ?missing though,
wouldn't it be safer to explicitly define a
default value of NULL:
myplot <- function(x, y=NULL) {
if(is.null(y)) {
y <- x
x <- 1:length(y)
}
plot(x, y)
}
[snip] In my opinion the missing() functionality can indeed be fragile (for example, I don't know how I can manipulate an existing call to make an argument be 'missing' when it was previously 'non-empty') and using an explicit NULL is often a good idea. This makes the documentation a tiny bit less wieldy if you have lots of parameters ...
An embedded and charset-unspecified text was scrubbed... Name: not available URL: <https://stat.ethz.ch/pipermail/r-devel/attachments/20130717/7d082bf3/attachment.pl>
I agree that failing fast is a good principle. My initial point led the other way though, i.e. any unmatched formal arguments without default values should be handled in one of two ways: 1. Fail the function call. This is what most non-functional languages do e.g. Python
def f(x,y,z): x
...
f(2)
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: f() takes exactly 3 arguments (1 given) 2. Perform partial application, like some functional languages e.g. Haskell f :: Int -> Int -> Int -> Int f x y z = x *Main> let a = f 2 *Main> :t a a :: Int -> Int -> Int Otherwise if an argument is truly optional, I don't see why a default value cannot be assigned to the formal argument when defining the function (excepting the edge cases you pointed out earlier). Brian
On Jul 17, 2013, at 2:35 PM, Peter Meilstrup <peter.meilstrup at gmail.com> wrote:
On Wed, Jul 17, 2013 at 10:20 AM, Ben Bolker <bbolker at gmail.com> wrote:
Brian Rowe <rowe <at> muxspace.com> writes:
Thanks for the lead. Given the example in ?missing though,
wouldn't it be safer to explicitly define a
default value of NULL:
myplot <- function(x, y=NULL) {
if(is.null(y)) {
y <- x
x <- 1:length(y)
}
plot(x, y)
}
[snip] In my opinion the missing() functionality can indeed be fragile (for example, I don't know how I can manipulate an existing call to make an argument be 'missing' when it was previously 'non-empty')
Like so:
thecall <- quote(x[i,j]) thecall[[3]] <- quote(expr=) thecall
x[, j]
and using an explicit NULL is often a good idea. This makes the documentation a tiny bit less wieldy if you have lots of parameters ...
I could certainly imagine a variant of R in which missing and NULL are unified, and NULL is the default for any binding that exists but was not given a value. I would probably prefer it on the grounds of being smaller and more consistent. (At the C implementation level, R_MissingArg and R_NilValue are just two parallel uses of the null object pattern with different behavior, which is a bit silly) But one advantage the missing value behavior can have is that it "fails early", i.e. it generates an error closer to where a function wants to use a value it was not provided, rather than "failing late," where a NULL propagates though your data and you have to do more debugging work to find out where it came from. This kind of fragility can be a good thing as it's easier to debug problems that happen closer to the point of failure. For instance,
myplot <- function(y, x=1:length(y)) plot(x,y) myplot()
Error in plot(x, y) (from #1) : error in evaluating the argument 'x' in selecting a method for function 'plot': Error in length(y) (from #1) : 'y' is missing I didn't think about what myplot should do with no arguments. As it turns out it is an error, as R refuses to pass a missing value along to length() or plot(), which is reasonable. Compare with a default-NULL version.
myplot <- function(y=NULL, x=1:length(y)) plot(x,y) myplot()
Instead of failing early and generating a stack trace pointing you at the problem, myplot() now generates a graph with points at (0,0) and (1,1) -- most surprising! This is because R happily forwards NULL to length() and plot() where it refused to earlier. In more complicated code nulls can pass along several layers before causing problems, making those problems more of a headache to debug. Peter [[alternative HTML version deleted]]
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel