Skip to content

Instantly share code, notes, and snippets.

@cscherrer
Created November 22, 2021 19:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cscherrer/df2fd33b7dbda3b3aba82a28e3a8a54e to your computer and use it in GitHub Desktop.
Save cscherrer/df2fd33b7dbda3b3aba82a28e3a8a54e to your computer and use it in GitHub Desktop.
Method wrappers, by Mason Protter
# Origin:
# https://julialang.zulipchat.com/#narrow/stream/274208-helpdesk-.28published.29/topic/Constraining.20method.20signatures/near/262358928
struct MethodWrapper{F, T <: Tuple, R}
f::F
end
MethodWrapper(f::F, Ts) where {F} = MethodWrapper{F, toTuple(Ts), Any}(f)
MethodWrapper(f::F, (Ts, R)::Pair) where {F} = MethodWrapper{F, toTuple(Ts), R}(f)
toTuple(::Type{T}) where {T} = Tuple{T}
toTuple(Ts::Tuple) = Tuple{Ts...}
(M::MethodWrapper{F, Ts, R})( args...) where {F, Ts, R} = invoke(M.f, Ts, args...)::R
(M::MethodWrapper{F, Ts, Any})(args...) where {F, Ts} = invoke(M.f, Ts, args...)
function Base.show(io::IO, M::MethodWrapper{F, T, R}) where {F, T <: Tuple, R}
Ts = collect(T.parameters)
print(io, string(M.f), "(::$(Ts[1])", (", ::$(Ts[i])" for i in 2:length(Ts))..., ")::$R")
end
macro method(ex::Expr)
@assert ex.head ∈ (:call, :(::))
if ex.head == :call
R = Any
else
R = ex.args[2]
ex = ex.args[1]
end
f = ex.args[1]
Ts = map(ex.args[2:end]) do arg::Expr
@assert arg.head == :(::)
arg.args[length(arg.args)]
end
esc(:(MethodWrapper($f, ($(Tuple(Ts)...),) => $R)))
end
##########################################################
f(x, y) = x^2 + 2x*y
m = @method f(::Real, ::Complex) :: Complex
#+RESULTS:
f(::Real, ::Complex)::Complex
##########################################################
typeof(m)
#+RESULTS:
MethodWrapper{typeof(f),Tuple{Real,Complex},Complex}
##########################################################
m(1, 1 + im)
#+RESULTS:
3 + 2im
##########################################################
m2 = @method f(::Real, ::Complex)::Real
m2(1, 1+ im)
#+RESULTS:
TypeError: in typeassert, expected Real, got a value of type Complex{Int64}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment