Functions and callable methods

I am confused about how to organize my code for objects which behave like functions. Some functions do different things when called with arguments which are <: Function, eg Plots.plot will plot the function, but will not plot a callable object which is not <: Function (because it can’t dispatch on it, unless a recipe is defined etc).

Generally, a type T

  1. can have (f::T)(...) methods defined, and
  2. T <: Function can hold.

Apparently these two are orthogonal, one can have a <: Function without it being callable, and vice versa. I am wondering if it is good style to impose both at the same time, or if there are good arguments for doing one but not the other.

Sorry if the question is vague. I am assuming that others have ran into this and would like to hear what you think.

2 Likes

I have also run into this a couple of times when writing functions that accept functions.

In general I try to avoid dispatching on ::Function to allow passing callable objects, but sometimes that is quite difficult to pull off. There is this convention of putting optional functions as the first argument to allow for the f(...) do ... end syntax. But especially a flexible first argument type can easily cause ambiguities

@Evizero is correct that it’s often best to avoid restricting the dispatch. This advice also generally applies to more than just Functions.

To further his point, I would suggest that making a subtype of Function can be more generally be treated as a trait property of the type. Thus it’s not inherently meaningful (as you noted, being actually callable is an orthogonal property – and having an applicable method is also entirely different). But as a trait, it is useful for informing dispatch that it is intended for this object to be treated as a Callable. Does that make sense?

1 Like