14 Argument meaning should be independent
14.1 What’s the problem?
Avoid having one argument change the interpretation of another argument. This makes reading function calls harder because if the argument that changes meaning comes after the argument who’s meaning is changed you need to reinterpret the rest of the call.
14.2 What are some examples?
-
In
library()
thecharacter.only
argument changes how thepackage
argument is interpreted: In
install.packages()
settingrepos = NULL
changes the interpretation ofpkgs
from being a vector of package names to a vector of file paths.In the base R string functions,
perl
andfixed
change the interpretation of thepattern
argument. See Section 17.3 for more details.In
ggplot2::geom_label()
, settingparse = TRUE
changes the meaning of the label argument/aesthetic from being any string to be a string on unparsed R code.In
readr::locale()
there’s a complex dependency betweendecimal_mark
andgrouping_mark
because they can’t be the same value, and Europe and the US Europe use different standards. That suggests it might have been better to specify them in a single argument likemarks = c(",", ".")
.In
findInterval()
if you setleft.open = TRUE
therightmost.closed
meansleftmost.closed
.
14.3 How do I remediate past mistakes?
Not clear that there’s a single solution. For the examples above:
-
In
library()
, I think this is an example of why base R needs a consistent mechanism for quoting and unquoting. Iflibrary()
were a tidyverse function it would use tidy-eval, and so you’d writelibrary(ggplot2)
orlibrary(!!ggplot2)
.Alternatively, you could maybe argue that it should be
library("ggplot2")
andlibrary(ggplot2)
. In
install.packages()
maybe it would be better to have mutually exclusivepackages
andpaths
arguments? Thenrepos
only applies topaths
which might suggest this is an example of the strategy pattern?grepl()
and friends are another example of the strategy pattern.For
ggplot2::geom_label()
my gut feeling would be to make it another function, butparse = TRUE
applies togeom_text()
as well. So maybe the current setup is the least worst?In
findInterval()
I think I’d fix it by renaming the argument to something that wasn’t direction specific. Maybeextemum.closed
?