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

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

julia> struct MyInt <: Integer

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

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

julia> 1:6
ColumnRange(1, 6)

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

julia> function f(x::ColumnRange)
           println("doing work with x::ColumnRange")
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

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: