I happened to stumble across Wikipedia’s page on Multiple dispatch and noted that (at the time) Julia’s only mention was a single link, and all serious discussion was focused on other languages (many of which do not have native support for MD).
If you follow that link, you’ll see I fixed that . In particular, folks may be interested in the graphs I added analyzing the usage of multiple dispatch in practice. For archival purposes, here’s my analysis code:
# Pairwise comparison of argument types in method signatures
struct ArgSharingCounts
# counts by argument position of same/different
# argsame[n][s] or argdiff[n][s]: methods with n arguments, comparing slot s
argsame::Vector{Vector{Int}}
argdiff::Vector{Vector{Int}}
# histogram of total numbers of identical arguments
# histsame[n][k]: number of method-pairs with n arguments of which k-1 are the same
histsame::Vector{Vector{Int}}
end
ArgSharingCounts() = ArgSharingCounts(Vector{Vector{Int}}(0), Vector{Vector{Int}}(0), Vector{Vector{Int}}(0))
Base.length(asc::ArgSharingCounts) = length(asc.histsame)
function grow_to!(asc::ArgSharingCounts, n)
while (m = length(asc)) < n
push!(asc.argsame, zeros(Int, m+1))
push!(asc.argdiff, zeros(Int, m+1))
push!(asc.histsame, zeros(Int, m+2)) # histogram has extra slot for k=0 case
end
asc
end
sig(m::Method) = sig(m.sig)
sig(s) = s
sig(s::UnionAll) = Base.unwrap_unionall(s)
function Base.push!(asc::ArgSharingCounts, m1::Method, m2::Method)
p1, p2 = sig(m1).parameters, sig(m2).parameters
(l = length(p1)) == length(p2) || return asc
grow_to!(asc, l-1) # first arg is typeof(f), skip it
k = 0
for i = 1:l-1
if p1[i+1] == p2[i+1]
asc.argsame[l-1][i] += 1
k += 1
else
asc.argdiff[l-1][i] += 1
end
end
asc.histsame[l-1][k+1] += 1
asc
end
funcdict = Dict{Symbol,ArgSharingCounts}()
for name in names(Base)
@show name
f = getfield(Base, name)
if isa(f, Function)
mths = collect(methods(f))
asc = ArgSharingCounts()
for j = 1:length(mths)
mj = mths[j]
for i = 1:j-1
mi = mths[i]
push!(asc, mi, mj)
end
end
funcdict[name] = asc
end
end
# Total counts
asct = ArgSharingCounts()
for (fsym, asc) in funcdict
grow_to!(asct, length(asc))
for i = 1:length(asc)
asct.argsame[i] .+= asc.argsame[i]
asct.argdiff[i] .+= asc.argdiff[i]
asct.histsame[i] .+= asc.histsame[i]
end
end
# normalized analysis of 2-argument functions
nmethods = Int[]
p0 = Float64[]
p1 = Float64[]
for (fsym, asc) in funcdict
if length(asc) >= 2
push!(nmethods, length(collect(Iterators.filter(m->length(sig(m).parameters)==3, methods(getfield(Base, fsym))))))
nt = sum(asc.histsame[2])
if nt > 0
push!(p0, asc.histsame[2][1]/nt)
push!(p1, asc.histsame[2][2]/nt)
end
end
end
using Gadfly
phist = plot(x=nmethods, Guide.xlabel("with # methods"), Guide.ylabel("# 2-arg funcs"), Scale.x_log10, Geom.histogram);
pshared = plot(x=p0, Guide.xlabel("Frac. pairs, 0 shared arguments"), Guide.ylabel("Count"), Geom.histogram, Coord.Cartesian(xmin=0.0, xmax=1.0));
vstack(phist, pshared)