-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
Consider a Julia neophyte trying to sort Chars:
julia> maximum('A', 'B')
ERROR: MethodError: objects of type Char are not callable
Stacktrace:
[1] mapreduce_first(::Char, ::Function, ::Char) at ./reduce.jl:293
[2] mapfoldl_impl(::Char, ::Function, ::NamedTuple{(),Tuple{}}, ::Char) at ./reduce.jl:60
[3] #mapfoldl#186(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(mapfoldl), ::Char, ::Function, ::Char) at ./reduce.jl:72
[4] mapfoldl(::Char, ::Function, ::Char) at ./reduce.jl:72
[5] #mapreduce#194(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(mapreduce), ::Char, ::Function, ::Char) at ./reduce.jl:200
[6] mapreduce(::Char, ::Function, ::Char) at ./reduce.jl:200
[7] maximum(::Char, ::Char) at ./reduce.jl:524
[8] top-level scope at none:0
Of course they should have used max. But that stack trace is long and confusing, considering that already the very first call maximum(::Char, ::Char), the types are all wrong for maximum. Normally, Julia methods have a signature that takes only appropritate abstract types, like Number and so on, precisely so that the method only apply to inputs of the correct types.
The problem is that there are no types for Callable or Iterable, so the signature of maximum is totally untyped: maximum(f, a) = mapreduce(f, max, a).
To solve this, I suggest implementing Holy traits Iterable and Callable:
maximum(f, itr) = maximum(f, callable(f), itr, iterable(itr))
maximum(f, ::Callable, itr, ::Iterable)
One argument against doing this is that it could open the door to all kinds of traits in Base for this or that property. However, in my experience, it seems like the properties "iterable" and "callable" are particularly often used, just consider the amount of confusion about what is iterable or not we often see.