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...))

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...))

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...))
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)
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.