Getting this type signature correct

Say I have a function that accepts at least one argument of Union{Int, Colon, OrdinalRange}. I can write this like:

function test(i::Union{Int, Colon, OrdinalRange}, I::Union{Int, Colon, OrdinalRange}...)
    println((i, I...))
end

But that’s a tad verbose. I could obviously create a typedef for the Union, but let’s say this is a one-off function and I’d rather avoid polluting my namespace. So I tried:

function test(I::P, I::P...) where P <: Union{Int, Colon, OrdinalRange}
    println((i, I...))
end

However, this fails with MethodError when called with 2 arguments. For example, if I call test(1, 2), this correctly matches on the first argument, but not on the second argument.

Why is this?

When I use your second definition, test(1, 2) works for me, but test(1, :) does not:

julia> function test(i::P, I::P...) where P <: Union{Int, Colon, OrdinalRange}
           println((i, I...))
       end
test (generic function with 1 method)

julia> test(1, 2)
(1, 2)

julia> test(1, :)
ERROR: MethodError: no method matching test(::Int64, ::Colon)
Closest candidates are:
  test(::P, ::P...) where P<:Union{Colon, Int64, OrdinalRange} at REPL[2]:1

The reason is because the second definition declares that all the arguments are of the same type P. So your second definition is not equivalent to the first definition, because in your first definition the arguments can be of different types.

1 Like

Duh. Yes, of course! Thanks for that @CameronBieganek!

1 Like

By the way, you can use a let block if you want to have a local type alias that doesn’t pollute your namespace:

julia> let
           T = Union{Int, Colon, OrdinalRange}
           global foo(x::T, y::T...) = (x, y)
       end
foo (generic function with 1 method)

julia> foo(1, :)
(1, (Colon(),))

julia> T
ERROR: UndefVarError: T not defined

Though in this case I would probably just write it out the long way.