Scalar function for reals and arrays: single function definition

I often find myself writing two methods for a simple scalar function. E.g.

function gauss(x::Real; a=1.0, c=0.0, s=0.7)
    return a/s/(sqrt(2pi))*exp(-((x-c)^2/(2*s^2)))
end

function gauss(x::AbstractArray{<:Real}; a=1.0, c=0.0, s=0.7)
    return [gauss(xx, a=a, c=c, s=s) for xx in x]
end

xs = -5:0.01:5
ys = gauss(xs)

Could this be reduced to a single function definition that dispatches on single scalar types and arrays of reals?

Could you use broadcasting ys = gauss.(xs)? That’d be the most common idiomatic way to make scalar functions work on each element of an array. Otherwise, I think you’d need to make extra forwarding methods like so.

3 Likes

The point being: don’t make a special version for arrays at all (not even one that uses broadcasting internally), only make the scalar version, and call it with dot broadcasting.

3 Likes

Exception: an array, likely with a static size, is the indivisible data point, in which case you’d make a function working on them and could broadcast it over arrays of such arrays.

1 Like

Oh, sure, functions that are inherently meant to take arrays as a fundamental working unit (like e.g. linear algebra, too). But functions that are inherently scalar ‘by nature’ should just be defined scalars, and broadcasted at the call site.

Another possible exception is if there are common calculations that can be avoided by specializing, or other significant optimization opportunities.

2 Likes

Thanks a lot for your comments! (:

1 Like

Conflating 1-element vectors and scalars is tempting, and useful in many cases, but keeping stricter separation promotes clarity and may circumvent some bugs through static analysis and better design. The latter seems to weigh heavier in most cases.

1 Like