# Understanding UnionAll types

**URL:** https://discourse.julialang.org/t/understanding-unionall-types/16288
**Category:** General Usage
**Created:** [October 13, 2018, 6:41pm UTC](https://discourse.julialang.org/t/understanding-unionall-types/16288 "2018-10-13T18:41:30Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![mdsalerno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mdsalerno/32/5539_2.png) [@mdsalerno](https://discourse.julialang.org/u/mdsalerno)
#### Post date: [October 13, 2018, 6:41pm UTC](https://discourse.julialang.org/t/understanding-unionall-types/16288/1 "2018-10-13T18:41:30Z")

</div>

Reading through the documentation on constructors, I came across this example.

```julia
struct OurRational{T<:Integer} <: Real
    num::T
    den::T
    function OurRational{T}(num::T, den::T) where T<:Integer # why is this UnionAll necessary?
        if num == 0 && den == 0
            error("invalid rational: 0//0")
        end
        g = gcd(den, num)
        num = div(num, g)
        den = div(den, g)
        new(num, den)
    end
end

```

The documentation explains " The first line – `struct OurRational{T<:Integer} <: Real` – declares that `OurRational` takes one type parameter of an integer type, and is itself a real type."

Can someone break down the signature of the inner constructor in a similar manner? I’m particularly thrown off by the need for a UnionAll type here.

As I currently understand it, the `where T<:Integer` means we are defining several ` OurRational{T}(num::T, den::T)` one for each subtype of Integer. Why is it not possible to instead do something like `function OurRational{T<:Integer}(num::T, den::T)` without the UnionAll? When I do so, I get an error saying there are too few type parameters specified in `new{...}`, so I edit that line to read `new{T}(num, den)`, which results in a “T is not defined” error.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [October 13, 2018, 7:23pm UTC](https://discourse.julialang.org/t/understanding-unionall-types/16288/2 "2018-10-13T19:23:07Z")

</div>

In older versions of Julia, we had a syntax like what you’re suggesting (`OurRational{T<:Integer}(...)`, but it came with a significant problem: there was no obvious way to distinguish parameters of a function (which are just restrictions on the argument type) from explicit parameters of a type specified by a user. This is easier to explain with an example. Let’s say you defined a method using the old syntax:

```julia
function foo{T <: Integer}(x::T)
  x + 1
end

```

If `foo` is a function, then this defines a method which a user might call using `foo(1)`. But what if `foo` is actually a type? Then this is a constructor, but is it one you’d call using `foo{Int}(1)` ? Or is it one you’d call with `foo(1)` ? I honestly don’t remember which way it used to work, and I think it changed at least once. Both of those cases had what you would now call a `UnionAll`: there is some parameter `T` with some restrictions on its type, and the specific type is determined from the arguments (or maybe from the explicit `Int` in `foo{Int}(1)`, hence the confusion).

The `with` keyword doesn’t really change the fact that there is a type parameter, it just makes it much more explicit what’s going on (now we have a name for this behavior and can therefore control it). This allows us to write:

```julia
# In this case, the `T` is specified by the user 
# at the call site: foo1{T}(1)
function foo1{T}(x::T) where {T} 
  ...
end

```

and have it actually be different from:

```julia
# In this case, the `T` is not specified by the user
# at the call site: foo2(1)
function foo2(x::T) where {T}
  ...
end

```

The fact that you’re looking at an inner constructor is now almost completely irrelevant. You would write exactly the same function as an outer constructor, except that you wouldn’t be able to call `new()` directly.

I think part of your question is also why the `where {T <: Integer}` is not already implied by the `{T <: Integer}` on the first line. The answer to that is that there’s no assumption or requirement in Julia that the parameters of a given constructor will be the same as the parameters of the type itself. In your case, there’s just one parameter and it’s obviously the same as the parameter of the type, but that’s not generally true. For example, the `Array{T, N}` type has two parameters (the element type and the number of dimensions), but it has constructors that take 0, 1, or 2 parameters.

---

<div class="post-metadata">

### Author: ![mdsalerno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mdsalerno/32/5539_2.png) [@mdsalerno](https://discourse.julialang.org/u/mdsalerno)
#### Post date: [October 21, 2018, 6:34am UTC](https://discourse.julialang.org/t/understanding-unionall-types/16288/3 "2018-10-21T06:34:57Z")

</div>

Really appreciate the detailed answer. The examples especially cleared up a lot of confusion.
