I have a function “counts” that divides a sorted array of floats into subarrays based off a specified maximum value and an integer number of divisions, and then counts the length of each subarray, returning an array of lengths - the “counts” of each subsection. Currently it is something like
function counts(arr, max, divisions) ...
called with
counts(arr, 5.0, 5)
This function works fine for this, but I would like to overload the function to be able to express the required subsections as either an integer number of divisions, or a float interval size. This could be easily achieved by
function counts(arr, max, divisions :: Int) ...
function counts(arr, max, interval :: Float64) ...
However this could easily lead to misuse, where a user would get a very different result from using a float instead of an int. To avoid this, it would make sense to use keyword arguments, such that the function might be called with
counts(arr, 5.0, divisions = 5)
or
counts(arr, 5.0, interval = 1.0)
Thereby making it clearer to the user what they are doing. Exactly one of these should be required.
Here lies the problem. I can easily make keywords required by not assigning a default value
function counts(arr, max; interval :: Float64, divisions :: Int) ...
but I don’t want both to be required, since either one is sufficient, and preferably I don’t want the user to try and specify both since it can only lead to mistakes. I don’t think I can do this in separate definitions as when they were not keywords, since the second just overwrites the first definition. One workaround I can imagine is to assign both keyword arguments a default value (such as 0) and then have the function check that exactly one is assigned to a non-zero value, and throw an error if not. That makes some sense since the given argument should not be 0 anyway, but manually checking that the function has been given the correct number of arguments feels wrong. Alternatively I could have an overload with one mode as a required keyword and the other not a keyword:
function counts(arr, max, divisions :: Int) ...
function counts(arr, max; interval :: Float64) ...
which I have a feeling some native functions may do. Is this the best approach?