I just read up on Unions, and I get the impression that approach A and B below would be exactly equivalent:

``````int32_only_eater(i::Int32) = println(i)

# Approach A
eatint(i::Int32) = int32_only_eater(i)
eatint(i::Int64) = int32_only_eater(convert(Int32,i))
eatint(i::Float64) = int32_only_eater(convert(Int32,i))

# Approach B
typealias IntUnion Union{Int32,Int64,Float64}
eatint2(i::IntUnion) = int32_only_eater(convert(Int32,i))
``````

Is that correct? If so, I have been making my life needlessly complicated by using approach A.

2 Likes

Not (currently) for ambiguity resolution purpose.

1 Like

And for possible change of ambituity detection in the future, itâ€™s a matter of whether `f(::Union{A,B},::A)` and `f(::A,::Union{A,B})` should be an method redefinition warning or an ambiguity.

1 Like

I understand the ambiguity in this example, but in cases where there is no ambiguity isnâ€™t it the same as writing out all permutations of arguments? (this seems strangely circular, but I hope you know what I mean)

In particular, for the 1-argument example in the original post, arenâ€™t the two approaches the same?

Thatâ€™s what I said. They are not the same for the purpose of ambiguity detection and therefore dispatch. You can get ambiguity with only a single argument without any problem.

``````julia> f(::Union{Int,Float32}) = 1
f (generic function with 1 method)

julia> f(::Union{Int,Float64}) = 2
f (generic function with 2 methods)

julia> f(1)
ERROR: MethodError: f(::Int64) is ambiguous. Candidates:
f(::Union{Float64, Int64}) in Main at REPL[2]:1
f(::Union{Float32, Int64}) in Main at REPL[1]:1
``````

A quick check with `@code_native` seems to indicate they generate the same code at least. I think in my application the ambiguities are not really an issue, itâ€™s mostly in the context of CxxWrap to make it easier to pass things like unsigned integers to C++ (i.e. without asking users to put UInt() around arguments) and also to allow passing an object and its smart pointer to the same function. Currently I have code that indeed generates all permutations for all requested overloads, so I was hoping to simplify this using Unions.

Well, the signature you specify only affect dispatch and only in very rare cases affect code generation (`Function` and `Type`) so in that sense, nothing you put there affect specialization and `Union` is totally irrelevant here.

And of course they affect dispatch more than just ambiguity detection because it can affect `invoke` too for the same reason.

``````julia> invoke(f, Tuple{Union{Int,Float32}}, 1)
1
``````

Yes, I shouldnâ€™t have said â€ś1-argumentâ€ť, but rather the circular-sounding â€śwhen there are no ambiguitiesâ€ť.
I was interpreting the original question as whether these are identical:

``````f(::Union{Int,Float32}) = 1
``````

and

``````f(::Int) = 1
f(::Float32) = 1
``````

As I said

• For performance it doesnâ€™t matter whatever you put in the signature. Whether it is `Union` or not.
• For dispatch, it matters for certain cases and doesnâ€™t matter for other cases.
If your question is if it doesnâ€™t matter for the cases it doesnâ€™t matter than the answer is obviously yes. My two comments above are just pointing out the cases that I can think of where it does matter.

OK, I think I finally get it. Thank you.

As you said, â€śmethod redefinition warning or an ambiguityâ€ť.

The following was instructive for me:

``````julia v0.5.0> f(::Union{Int,Float32}) = 1
f (generic function with 1 method)

julia v0.5.0> f(::Union{Int,Float64}) = 2
f (generic function with 2 methods)

julia v0.5.0> f(1)
ERROR: MethodError: f(::Int64) is ambiguous. Candidates:
f(::Union{Float64,Int64}) at REPL[2]:1
f(::Union{Float32,Int64}) at REPL[1]:1
``````

Separate definitions:

``````julia v0.5.0> f(::Int) = 1
f (generic function with 1 method)

julia v0.5.0> f(::Float32) = 1
f (generic function with 2 methods)

julia v0.5.0> f(::Int) = 2
WARNING: Method definition f(Int64) in module Main at REPL[1]:1 overwritten at REPL[3]:1.
f (generic function with 2 methods)

julia v0.5.0> f(::Float64) = 2
f (generic function with 3 methods)

julia v0.5.0> f(1)
2
``````

OK, thanks for the replies, as usual things arenâ€™t as simple as they appear on the surface I conclude that for CxxWrap what currently results in a method redefinition warning will become an ambiguity error if I switch to Unions. Since redefinition warnings here indicate that a wrapped C++ function is masked by another, they also must be treated as errors, so I can safely switch to the Union approach.