If I want to know how many arguments a function has, i can do something like length(formals(func))
This works for my functions, but not for some base R functions like is.character (perhaps because its compiled?)
Reprex below
# Create a function with 3 arguments
func <- function(a, b, c){
message(a, b, c)
}
# Can get number of args with length & formals
length(formals(func))
#> [1] 3
# But this doesn't work for certain base R functions
length(formals(is.character))
#> [1] 0
I don't think so; as you've found there is a clear difference between normal functions and primitive functions.
you an test if a function is primitive by is.primitive
> is.primitive(as.character)
[1] TRUE
You could try a hacky approach using string processing ; get hold of the strings like
capture.output(args(as.character))[[1]]
but there are lots of interesting edge cases even with normal functions.
length(fn_fmls(mean))
# 2
How do you intend to interpret ... ?
as 1 or as Infinite ?
You raise some interesting points @nirgrahamuk. Thanks for your response!
I'm interested in writing functions that assert basic features of functions
Your insights make me think two basic functions need to be available:
a function that returns a count of named arguments,
a function that returns a boolean describing whether dots ... are used as an argument
From these you could build other functions that assert there are 'at least X' arguments. Then I'd leave it up to the end user whether ... should count as Infinite (default yes), or perhaps just throw an error (think function that takes a very specific 2 argument function the user will likely have to create - here asserting exactly 2 named arguments and ignoring or throwing an error if ... is present seems perfectly reasonable.
I think having some 'ellipses_value' argument that could be 1 or Inf , might push users of these functions (i.e. future me ) to think about exactly what they want to assert.
I will leave this topic open another couple of days on the off chance anyone has a less hacky way to handle primitives.
We can additionally get the names simply by adding: names(formals(args(as.character))).
# Get argument names (Primitives)
names(formals(args(as.character)))
#> [1] "x" "..."
# Get number of arguments (Primitives)
length(formals(args(as.character)))
#> [1] 2
# Get argument names (Non-Primitive)
names(formals(args(mean)))
#> [1] "x" "..."
# Get number of arguments (Non-Primitive)
length(formals(args(mean)))
#> [1] 2