Chaining calls to the binary .. operator

Is there a way I can create a unary operator function that can function like:

using Dates

..(x::Int,y::Int,z::Int)=Date(x,y,z)

-> 2022..1..1 == Date(2022,1,1)

true

I can catch a solution like:

struct I{T}
    x::T
    y::T
end

(..)(x, y) = I(x, y)

(..)(x::I{Int},y::Int)=I(x.x,x.y,y)


But then I have to write this to generate a Date

(2022..1)..1

Is there a more simple way to do this?

The .. operator doesn’t support chaining like that.

One way to define custom constructor syntax is to use a string macro, which lets you parse expressions in any way that you want (completely independent of standard Julia syntax). For example:

julia> macro date_str(s)
           args = Meta.parse.(split(s, '-'))
           :(Date($args...))
       end
@date_str (macro with 1 method)

julia> date"2022-4-20"
2022-04-20

(Though I’m not convinced that this particular example is much clearer than just typing Date(2022, 4, 20), it certainly seems a lot clearer than 2022..4..20.)

PS. What you are describing is not a unary operator — it is a binary operator .. that you want to chain without using parentheses. I’m not sure why the .. doesn’t support chaining, but many other custom operators do, e.g.

julia> :(3⨳4⨳5)
:((3 ⨳ 4) ⨳ 5)
3 Likes

You can use the ++ operator:

julia> using Dates

julia> ++(x, y, z) = Date(x, y, z)
++ (generic function with 1 method)

julia> 2022++1++1
2022-01-01
3 Likes

Thanks for your help.

Yes, It`s really confusing that this operator does not support chaining while some others can.

I find another way to do that:

Base.:(~)(x,y)=I(x,y)
Base.:(~)(year_num::Int,i::I{Int})=Date(year_num,i.x,i.y)

-> 2022~1~1
2022-01-01

First, while .. does not support chainning, so I have change it to ~; Second, It is also confusing that when calling 2022~1~1, It calls ~(1,1) firstly, then calls ~(2022,(1,1)). I thought it would be backward.

1 Like

Thanks for your help. ++ support any number of arguments, it would be the reason way ++ works while .. does not. I also find another way to do it with not having to use ++:

1 Like
julia> 2022++1++1
2022-01-01

It’s cool (and very surprising to me, possible), but not what I would want people to start using (for Dates nor ~). I’m not sure why, but unlike with ++, the example with 2022~1~1 didn’t work for me (in Julia 1.7.0 or 1.9):

julia> Base.:(~)(year_num::Int,i::I{Int})=Date(year_num,i.x,i.y)
ERROR: UndefVarError: I not defined

At least the latter is chaining, and whatever you want to call with ++ (chaining or) ternary operator, are there such ternary operator uses, in any Julia code base? For any operator (or just in math, at least very rare).

You have to define I first.