# Good etiquette for 2 optional arguments that can't both be used

I'll demonstrate with an example of the normal distribution in Python.

``````def norm_pdf(x, mu=0, v=1, p=1):
"""Returns un-normalized probability density of normal distribution at x.
mu: mean
v: variance
p: precision (inverse of variance)
"""
# if they specify v
return 2.71828**(-(x-mu)**2/v/2)
# if they specify p
return 2.71828**(-(x-mu)**2*p/2)
``````

The idea is the user should be able to specify the variance `v` or the precision (inverse variance) `p`, but not both. What is the proper way to deal with something like this? What is the etiquette that libraries like Numpy use in these cases? Normally, I'd like to overload the function, but `v` and `p` are the same type, so it's not that simple.

• It gets even worse if you also want to support standard deviation.
– J.G.
Commented May 5, 2020 at 17:36

For clarity, I would make two functions,

`norm_pdf_from_variance(x, mu, variance)` and

`norm_pdf_from_precision(x, mu, precision)`.

They could call a common "private" function to do the calculation.

The alternative is a single value v and a boolean `isPrecision`, but, that's a bad and confusing idea. Go for clarity.

An alternative to creating two different methods (as in user949300's answer is to use method overloading along with custom types to make it clear what the "number" you're passing in means. I'm not sure how practical it is in python with its implicit types, but it's probably possible. Here it is in pseudo-C#:

``````double norm_pdf(double x, double mu=0, Variance v)
{
return 2.71828**(-(x-mu)**2/  v.Value  /2);
}

double norm_pdf(double x, double mu=0, Precision p)
{
return 2.71828**(-(x-mu)**2*  p.Value  /2);
}
``````

See how I replaced the numeric value with a custom type, either Variance or Precision, that is explicit in its meaning. In the formula itself, I extract the value from the wrapper type (different languages will have different syntax for that, which might be implicit or explicit).

To call it, you would create an instance of that custom type from your base value. Again, the syntax might be a bit different between languages:

``````double norm_from_precision = norm_pdf(myX, mu, new Precision(0.9112));
double norm_from_variance = norm_pdf(myX, mu, new Variance(0.9112));
``````

The type itself is very simple. Some languages have better syntax for so called "newtypes", but it might be something like this:

``````public class Variance
{
public double Value {get;}
public Variance (double value)
{
Value = value;
}
}
``````
• Primitive obsession is a general issue and one shouldn't be afraid to wrap a primitive in a meaningful type; but you can make a similar argument for "custom type obsession". Defining a custom type only to be used in one method signature is overkill. In such a case, you're better off varying the method name rather than generating custom types just to create distinct signatures for an overloaded method. If (and only if) precision/variance were a relevant concept to the entire domain (not just one method), then creating the custom types can be warranted. Commented May 6, 2020 at 11:13
• Sure, you can go overboard with custom types. But if the OP's code uses Precision and Variance often, it makes sense. Either that or check if your statistics package has those types exported. Commented May 6, 2020 at 11:16

There are some good ways of doing this with overloads etc. But to answer your question about how its done in practice, we can look at a random example function from numpy or any stats library.

https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.random.normal.html

"Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. If size is None (default), a single value is returned if loc and scale are both scalars. Otherwise, np.broadcast(loc, scale).size samples are drawn."

Mathematicians program like its the 70's with lots of single character variables like `a`, `b`, `x` etc and are quite happy to perform conditional logic based on the inputs and only explain this in the docs.

They would pick one of the inputs to check first and ignore the second if it was populated