# Union as constructor fails on nightly

**URL:** <https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301>\
**Category:** General Usage\
**Created:** [October 14, 2018, 7:47am UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301 "2018-10-14T07:47:05Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [October 14, 2018, 7:47am UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/1 "2018-10-14T07:47:05Z")

</div>

In a package that I’m writing, I’m using a `Union` as a constructor (with dispatch to select one of the types from the union). Here’s a minimal working example:

```julia
struct N{X} <: Number
end

struct I{X} <: Integer
end

U{X} = Union{N{X}, I{X}}

U(X::Number) = N{X}()
U(X::Integer) = I{X}()
U(X::U) = X

i = U(1)
U(i)

```

The two last lines return the same thing, namely `I{1}()`. This is working fine in Julia 1.0 and 1.0.1.

However, in Julia 1.1.0-DEV.447 (source build) or recent nightly, I get this:

```julia
 ERROR: MethodError: Union{I{X}, N{X}} where X(::I{1}) is ambiguous. Candidates:
   (::Type{Union{I{X}, N{X}} where X})(X::Number) in Main at REPL[4]:1
   (::Type{Union{I{X}, N{X}} where X})(X::Integer) in Main at REPL[5]:1
   (::Type{T})(x::T) where T<:Number in Core at boot.jl:724
 Possible fix, define
   Union{I{X}, N{X}} where X(::I)

```

Defining `U(X::I) = X` (as suggested by the error message) does not help.

Am I doing something wrong here, or is there a problem in the Julia development branch?

Edit: It seems the change that breaks my code is this one: [fix a transitivity error in method specificity by JeffBezanson · Pull Request #29405 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/29405)  
The code works on 1.1.0-DEV.384 but fails on 1.1.0-DEV.385

---

<div class="post-metadata">

**Author:** ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)\
**Post date:** [October 17, 2018, 2:52am UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/2 "2018-10-17T02:52:09Z")

</div>

Your code does look rather ambiguous to me… did you try replacing `U(X::U) = X` by

```julia
U(x::N{X}) where {X} = x
U(x::I{X}) where {X} = x

```

This works for me in 1.0. (I haven’t downloaded any recent nightly).

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [October 17, 2018, 5:25am UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/3 "2018-10-17T05:25:22Z")

</div>

Thanks. Yes I had tried that. It does not help. It does not even help if I define `U(x::I{1}) = x` (which is too specific to be useful.)

I agree that my code “looks rather ambiguous”, but I’m not sure exactly where the ambiguity lies, and why it is only ambiguous when I use the type union as a constructor. The following code runs fine:

```julia
f(X::Number) = N{X}()
f(X::Integer) = I{X}()
f(X::U) = X
f(f(1)) # returns I{1}()

```

(The actual code that I’m trying to get to work is here: [GitHub - perrutquist/StaticNumbers.jl: Static numbers in Julia](https://github.com/perrutquist/StaticNumbers.jl) )

---

<div class="post-metadata">

**Author:** ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)\
**Post date:** [October 17, 2018, 12:50pm UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/4 "2018-10-17T12:50:54Z")

</div>

In your original post, `I{1}` is a subtype of both `Integer` and `U`, which are mutually incomparable, so the call `U(::I{1})` is ambiguous since there is a method `U(::U)` and `U(::Integer)` but not `U(::I{X})`. The usual way to break such an ambiguity is to define another method for the subtype, which is why I suggested defining `U(x::I{X}) where {X}`. I don’t understand why this didn’t work.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [October 17, 2018, 1:12pm UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/5 "2018-10-17T13:12:10Z")

</div>

Thanks for the explanation. Yes, this makes perfect sense.

I should have used this as an example:

```julia
struct N{X} <: Number
end

struct I{X} <: Integer
end

U{X} = Union{N{X}, I{X}}

U(X::Number) = N{X}()
U(X::Integer) = I{X}()

U(x::N{X}) where {X} = x
U(x::I{X}) where {X} = x

i = U(1)
U(i)

```

I think the problem is this definition in boot.jl:

```julia
(::Type{T})(x::T) where {T<:Number} = x

```

It seems, however I try, I can’t make a definition that is more specific than that, so I always get an ambiguity error. (Before #29405, Julia wasn’t able to detect the ambiguity.)

For now, my solution is simply to use a constructor with a different name from the type union.

---

<div class="post-metadata">

**Author:** ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)\
**Post date:** [October 17, 2018, 1:45pm UTC](https://discourse.julialang.org/t/union-as-constructor-fails-on-nightly/16301/6 "2018-10-17T13:45:15Z")

</div>

Your last message raises another point that I don’t understand and that isn’t documented in the manual, as far as I can see. If `T<:U`, and they each have constructors, is there any relationship between a constructor call `T(...)` and `U(...)`? Does the multiple dispatch mechanism sometimes cause a `T(...)` in the code to invoke a `U(...)` or vice versa (in the same way that `f(::T)` can invoke `f(::U)`? How about `convert` calls, i.e., can a `convert(T, ::Any)` call be handled by `convert(U,::Any)`? And what about the special case when `T` is of the form `A{X}` while `U` is `A`?
