How to check the possible parameters for a function in Julia
Sometimes I create functions that receive a function as parameter, but in Julia the type is Function without any information, so when the function pass as parameter is not right, the error message is not very informative:
By example:
julia> function fun_demo(f::Function)
values = [1.0, 2.3, 3.4]
return f.(values)
end
each (generic function with 1 method)
julia> fun_demo(sin)
3-element Vector{Float64}:
0.8414709848078965
0.7457052121767203
-0.2555411020268312
However, when the function is not right, the error is difficult to understand:
julia> fun_demo(lowercase)
ERROR: MethodError: no method matching lowercase(::Float64)
Closest candidates are:
lowercase(::T) where T<:AbstractChar at ~/packages/julias/julia-1.7/share/julia/base/strings/unicode.jl:249
lowercase(::AbstractString) at ~/packages/julias/julia-1.7/share/julia/base/strings/unicode.jl:540
Stacktrace:
...
That information is very confusing for the user that pass the function. I order to detect that, I have created a small function checkFunType:
function checkFunType(fun::Function,type::DataType)
if (type <: Tuple)
meths = methods(fun, type)
else
meths = methods(fun, Tuple{type})
end
return !isempty(meths)
end
So, we can do a more informative error message to user with:
function fun_demo(f::Function)
@assert checkFunType(f, Float64) "Error: 'fun_demo' requires a function that receive a float and function '$(f)' does not do that"
values = [1.0, 2.3, 3.4]
return f.(values)
end
In that case, the error is more useful:
ulia> fun_demo(lowercase)
ERROR: AssertionError: Error: 'fun_demo' requires a function that receive a float and function 'lowercase' does not do that
Stacktrace:
...
Of course, you can be more gentle that using @assert. The important think is that you can check the parameters that the function could receive, and act as you wish.
I have found it extremely useful when you are working with functions as parameters. I hope this could be useful for anyone.
PS It also work with generic types and with several parameters:
julia> checkFunType(sin, Int32)
true
julia> checkFunType(sin, String)
false
julia> checkFunType(sin, Real)
true
julia> checkFunType(+, Tuple{Int32, Int32})
true
julia> checkFunType(+, Tuple{Int32, String})
false