Comment by briancr
Yes there are lots of runtime checks.. unfortunately, but I always fork the time-consuming calculations into C anyway so those checks don’t really affect overall performance much.
Scripted functions have no set arity, and the same applies to callback C functions. Scripted functions collect their arguments inside an ‘args’ variable. Likewise, each C function has a single ‘argsType’ argument which collects the argument pointers & type info, and there are macros to help unpack them but if you want to do the unpacking manually then the function can be called variadically:
ccInt myCfunction(argsType args)
{ for (int a = 0; a < args.num; a++) printf(“%p\n”, args.p[a]); return 0; }
So all functions are automatically variadic.
It’s good to know that these GC/etc. solutions are even used by the big languages..
The "all functions are automatically variadic" design is a nice simplicity win. No overloading, no arity mismatches at call sites - just a uniform calling convention.
The argsType struct with pointer array and count is essentially how varargs works at the ABI level in C anyway, you've just made it explicit. And having the type info alongside the pointers means you get runtime type checking without the caller needing to pass format strings or sentinel values like traditional C varargs.
The tradeoff is you lose static arity checking at parse time, but for an embedded scripting use case that's probably fine - you're validating at runtime anyway and the error messages can be more helpful than "wrong number of arguments."
Do you have plans for optional/default arguments, or is that outside the scope? With variadic-by-default it'd be natural to just check args.num and use defaults for missing ones.