How to define an infix operator that can act on multiple arguments at once like `:`?

Forgive me if I am wrong, but why can : act on 3 arguments at a time as an infix operator?

julia> @which 1:2:3
(::Colon)(start::T, step::T, stop::T) where T<:Real in Base at range.jl:22

If I want to define a new operator , which does something the changes a global variable (for simplicity, I will just use + in my examples) but returns nothing, I cannot make it act like ::

→(a, b) = (a + b; nothing)
→(a, b, c, xs...) = (sum([a, b, c, xs...]); nothing)

julia> 1 → 2 → 3
ERROR: MethodError: no method matching +(::Int64, ::Nothing)
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
  +(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87
  +(::Union{Int16, Int32, Int64, Int8}, ::BigInt) at gmp.jl:534
 [1] →(a::Int64, b::Nothing)
   @ Main ./REPL[4]:1

That is, 1 → 2 → 3 is treated as (1 → 2) → 3, but 1 → 2 returns nothing, which hinders the → 3 operation. But this can work:

julia> →(1, 2, 3, 4)

How can I write my code to let the operate on my entire collection (1,2,3,4) but not iteratively?

You can’t.
Not with that symbol.
+, * and ++ can have any number of arguments.
: can have 2 or 3
- can have 1 or 2.

Everything else is either 1 only or 2 only.

But iirc you can and unicode sub/superscript modifiers to any of the ones mentioned to get a new operator that has the same variadicity as original form


And ++ as well.


But you can maybe fake it

struct Part

→(a,b) = Part(a,b)
→(x::Part, c) = foo(x.a, x.b, c)

foo(a,b,c) = ...

You could also write a macro to rewrite a line, but I will let someone to else demo that as it is :zzz:

1 Like