<p dir="auto">Now that <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="475389232" data-permission-text="Title is private" data-url="https://github.com/JuliaLang/julia/issues/32753" data-hovercard-type="pull_request" data-hovercard-url="/JuliaLang/julia/pull/32753/hovercard" href="https://github.com/JuliaLang/julia/pull/32753">#32753</a> has landed, for Julia 2.0+ , we should deprecate the <code class="notranslate">@evalpoly</code> macro.</p>
<p dir="auto">Consider a Julia neophyte trying to sort <code class="notranslate">Char</code>s:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; 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"><pre class="notranslate"><code class="notranslate">julia&gt; 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
</code></pre></div>
<p dir="auto">Of course they should have used <code class="notranslate">max</code>. But that stack trace is long and confusing, considering that already the very first call <code class="notranslate">maximum(::Char, ::Char)</code>, the types are all wrong for <code class="notranslate">maximum</code>. Normally, Julia methods have a signature that takes only appropritate abstract types, like <code class="notranslate">Number</code> and so on, precisely so that the method only apply to inputs of the correct types.</p>
<p dir="auto">The problem is that there are no types for <code class="notranslate">Callable</code> or <code class="notranslate">Iterable</code>, so the signature of <code class="notranslate"> maximum</code> is totally untyped: <code class="notranslate">maximum(f, a) = mapreduce(f, max, a)</code>.</p>
<p dir="auto">To solve this, I suggest implementing Holy traits <code class="notranslate">Iterable</code> and <code class="notranslate">Callable</code>:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="maximum(f, itr) = maximum(f, callable(f), itr, iterable(itr))
maximum(f, ::Callable, itr, ::Iterable)"><pre class="notranslate"><code class="notranslate">maximum(f, itr) = maximum(f, callable(f), itr, iterable(itr))
maximum(f, ::Callable, itr, ::Iterable)
</code></pre></div>
<p dir="auto">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.</p>