b-fg
b-fg

Reputation: 4137

Union type specialization within a function in Julia

Say I have a function where the c keyword argument is a Union type. Depending on the type for c I would like to do some stuff within the function:

function foo(a :: Integer, b :: AbstractFloat; c :: Union{Integer, AbstractFloat} = nothing)
    if typeof(c) <: AbstractFloat
        d = c / pi
    elseif typeof(c) <: Integer
        d = typeof(b)(c ^ 2)
    end
    return d
end

Is this the correct way for dealing with this scenario? Should I instead use the multiple dispatch for a more efficient implementation? I am also thinking in terms of performance here.

Thanks.

Upvotes: 2

Views: 338

Answers (1)

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69939

Some comments.

This part:

c::Union{Integer, AbstractFloat} = nothing

will not compile, you would have to write c::Union{Nothing, Integer, AbstractFloat} = nothing.

In general the typeof(c) <: AbstractFloat should be optimized out by the compiler since the compiler knows the exact type of c you are passing, so this style should not impact the performance of your code.

However, there are two considerations:

  1. Using multiple methods would probably lead to a cleaner code.
  2. If you use Union you have to be more careful when defining methods to avoid dispatch ambiguities. Here is an example:
julia> f(x::Int, y::Union{Int, Float64}) = "f1"
f (generic function with 1 method)

julia> f(x::Integer, y::Int) = "f2"
f (generic function with 2 methods)

julia> f(1, 1)
ERROR: MethodError: f(::Int64, ::Int64) is ambiguous.

which is sometimes considered as surprising (although it is a correct behavior technically)

EDIT. Here is an example when the compiler does not complain as it can always establish a more specific method:

julia> g(x::Int, y::Union{Int, Float64}) = "f1"
g (generic function with 1 method)

julia> g(x::Integer, y::Union{Int, Float64}) = "f2"
g (generic function with 2 methods)

julia> g(1, 1)
"f1"

Upvotes: 4

Related Questions