-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
A remark by @vtjnash, "it would be better not to use ::Function
in a signature, now that everything it callable, that distinction can be a bit fuzzy" during the functor -> function rewrite (originally here: #15696 (comment)) made me look at the situation a little closer, and the result did not make me exactly happy. Currently we have many higher order functions with ::Function
in their signature, some without any type restriction, some with ::Callable
, where Callable
is an alias for Union{Function,DataType}
. I would have loved to open a PR that changes the definition of Callable
to Any
and then use ::Callable
everywhere (to mark the points where possibly traits might be used in the future).
Unfortunately, this would lead to a great many ambiguities. The first problematic candidate I found was, ehem, findfirst
:
findfirst(A, v) # look for value v in array-like A
findfirst(testf::Function, A) # look for element in A where testf returns true
Obviously, without the ::Function
, this would be totally ambiguous. Furthermore, traits won't save the day, as conceivably, one could make arrays callable (coming directly from the little shop of call overload horrors).
The number of complaints that non-Function
callables cannot be passed to findfirst
seems to be relatively low, so I'm not suggesting any immediate action. However, settling on a guideline where to go in the long run might be a good idea. I see four main options:
- Use
::Function
everywhere. This is overly restrictive, but I still wonder how often one wants to pass non-Function
callables to higher-order functions in practice. - Use
::Callable
(with its present definition) everywhere. Somewhat less restrictive, and probably takes care of most cases where 1. would hurt in practice. (But actuallyCallable
is a misnomer, so it might be replaced with something better.) - Make the signatures as liberal as possible without introducing ambiguities. Obviously, this is least disruptive, but at the cost of inconsistency.
- Use
Any
forCallable
and use it everywhere, reworking the API if necessary to avoid ambiguities. Obviously, this would be quite disruptive, but once done, the API would be consistent and powerful.
I'm still undecided what I'd prefer. Please weigh in!