How to use colon based range syntax with other types?

Hi, I’m still making my first steps with Julia.

I have the need for a Range type struct in my code. First I tried to use UnitRange{Int64}. Later I found out that for my needs some of the predefined functions on UnitRange{Int64} were not exactly how I needed them. Instead of redefining these functions, I thought about using my own struct:

struct ColumnRange
    start::Int64
    stop::Int64
end

This solves my problems, but I’m no longer able to use the nice colon-based syntax.

Is there anything I could do to enable this syntax:

a = 10:12

and make sure that the type of a is ColumnRange and not UnitRange{Int64}?

Greetings, Peter

No, I don’t think that’s possible without committing type piracy. You can however do something like this:

julia> struct ColumnRange
           start::Int64
           stop::Int64
       end

julia> struct MyInt <: Integer
           val::Int64
       end

julia> (::Colon)(a::MyInt, b::MyInt) = ColumnRange(a.val, b.val)

julia> MyInt(3):MyInt(12)
ColumnRange(3, 12)

Unfortunately doesn’t solve the problem of using prettier syntax…

1 Like

You can define a local : function:

julia> struct ColumnRange
           start::Int64
           stop::Int64
       end

julia> (:)(a, b) = ColumnRange(a, b)
: (generic function with 1 method)

julia> 1:6
ColumnRange(1, 6)
3 Likes

That looks nice.

However, it looks like it shadows the basic : function defined somewhere in Range.jl.

What I ultimately want is that I can pass 1:2 like arguments to functions with ColumnRange parameters.

I’ve looked into converters, but they seem not to be called for function arguments.

Yes, you can’t have the same thing mean two different things in the same scope so you have to choose what you want it to be.

Just make a function that accepts UnitRange{Int} then and do the conversion yourself? Something like:

julia> struct ColumnRange
           start::Int64
           stop::Int64
       end

julia> function f(x::ColumnRange)
           println("doing work with x::ColumnRange")
       end
f (generic function with 1 method)

julia> f(x::UnitRange{Int}) = f(ColumnRange(first(x), last(x)))
f (generic function with 2 methods)

julia> f(1:5)
doing work with x::ColumnRange
7 Likes

Now I see the logical circle in my own thinking. Your suggestion with the function that accepts UnitRange{Int} as a parameter and doing the conversion inside the function, would not solve my original problem: I wanted to redefine the transpose(UnitRange{Int64}) function. However, in a way that would not shadow the original implementation. And this seems to the logical cycle, which is not solvable: one cannot have two functions with the same name and signature and also have different implementations.

The functions that I wanted to apply a new meaning are transpose(UnitRange{Int64}) and -(UnitRange{Int64}). I will now go the pragmatic way and just use different names for these functions.

This will make my code a little bit harder to read, but the user of my code will have the nice colon based syntax.

Thanks to you all for helping me think! :smiley: