When calling a function, the function itself is treated like a 2nd class citizen.
That is, the function is fixed and the dispatch system only considers the other arguments.
However, when broadcasting the function is treated on par with the other arguments.
I propose a method dispatch mechanism that first dispatches to a function that can be overloaded, much like the getproperty function has been introduced to overload calls to getfield.
The name invoke is already taken. Maybe the function name call would be suitable.
The ability to define functions like Base.call(f, x::MyNumberType, args...) or Base.call(f, A::MyCollection, args...)
could make it a lot easier to wrap numbers or collections with a new type.
Currently one may have to define over a hundred new methods just to wrap number types.
See package AbstractNumbers for an example.
With the proposed mechanims one could accommodate many functions with only a handfull of “call” overload methods, one for each method signature.
If you want to define a hierarchy of function types, you can already do this by defining your own “functor” types. Julia already has “call” overloading that treats the caller on the same footing as the arguments. It’s not clear what your proposal adds to this. (The other proposal you linked allows dispatch on the return type, which would be new.)
The problem with callable types is that One cannot exploit type hierarchies. My understanding is that one cannot define a „call“ on an abstract type? I think that happened in the v0.5 transition? One can get around it with macros, but it is a bit of work
For F:C\rightarrow D to qualify as a functor it has to satisfy 2 axioms
For any composable pair f,g\in C it must be that Fg\cdot Ff = F(g\cdot f)
For earch c\in C it must be that F(1_c) = 1_{Fc}
Just wanted to point this out, because the term functor is not arbitray, but has a very specific meaning, and I don’t really see how it applies in this context.