Is this a bug or is it intended?

When running the round() function without the default argument of x but with a digits argument, it rounds the digits argument, instead of the missing 'x' argument

> round(digits=5)
[1] 5
> round(digits=3.12)
[1] 3

This is obviously wrong, but I'm not sure if it is one of those things that is documented deep in some help page on lexical scoping and default parameter binding, or something nobody ever is 'creative' enough to try before so nobody has reported it?

1 Like

I am not sure why you think this is wrong. You are setting a scalar equal to 3.12 and then rounding that scalar. The fact that you call the scalar digits does not affect the outcome. The only time you run into problems is if you try to call the scalar digits and try to use the option digits at the same time. See the example below:

round(3.12)
#> [1] 3
round(x = 3.12)
#> [1] 3
round(x = 3.12, digits = 2)
#> [1] 3.12
round(digits = 3.12)
#> [1] 3
round(digits = 3.12, digits = 2)
#> Error in round(digits = 3.12, digits = 2): formal argument "digits" matched by multiple actual arguments

Created on 2020-05-20 by the reprex package (v0.3.0)

Thanks for the explanation, and it got me thinking. I think this seems wrong because (1) a missing required argument should signal an error, (2) a named argument should be bound to the variable you are naming; (3) a named argument should not be bound to another argument; and (4) no other functions do this (except signif).

I dug into the c code for this an found that when a single argument is given to these functions, it always interprets that as the x argument and never checks its name, and this is only done for round() and signif() and I think no other functions. Other functions will check for this, but for these two there is a missing check that either was an oversight or someone did it purposely for some reason that is undocumented.

1 Like

So, you are thinking that round(digits = 3.12) should return an error? The only required argument for the function is the number to round, which would give you the default 0 digits. Or are you worried about this possibility?

round(digits = 3.12, 1)
#> [1] 1

The x object is not preserved after the command, so the name never really comes into play. You can, of course, do the following if you want to freak out people reading your code:

digits = 3.12
round(digits)
#> [1] 3
round(digits, digits = 1)
#> [1] 3.1

In general, R will let you name things almost what you want (not that you should for your own sanity sake however), so I do not see anything inherently wrong with being able to call an object "digits".