Julia: make `<|` right associative

Created on 15 Oct 2017  ·  5Comments  ·  Source: JuliaLang/julia

Dear all,
I just stumpled upon this weird thing: in julia 0.5 the operator <| is left associative.
This is a big surprise to me and hence I am issueing this here.

I wanted to define <| to be the opposite of |>, i.e. something like haskells dollar sign operator.
It already has the same operator precedence, however not the opposite associativity. For me this looks like a bug indeed, as the symbol directly suggests opposite associativity.

Others also tried to have an operator for this and came up with using for example, see https://stackoverflow.com/questions/41733532/does-julia-have-an-operator-similar-to-haskells-dollar-sign/41735969

Can this changed be still included up until julia 1.0 is out and nothing like this can be changed anymore?
that would be really great to have both |> and <| as opposites

decision parser

Most helpful comment

Quoting @JeffBezanson in https://github.com/JuliaLang/julia/issues/23224#issuecomment-336724709:

Maybe leftward arrows should also be right-associative?

I think this is the correct answer. We should be conservative with any operator we're not sure what the behavior of it should be. We can always add them later once we've sorted it out but there's a significant chance of being stuck with unusable syntax due to mistakes like this that we can't change. Of course, this is precisely the sort of thing that femtocleaner can easily fix, but changing associativity is very much a breaking change.

All 5 comments

My gut feeling is that this is a good idea, but I do wonder if there are any other candidates for right-associativity?

Can this changed be still included up until julia 1.0 is out and nothing like this can be changed anymore?

Technically things like this could change in something like Julia v2,0, but we are hoping to minimize the need for breaking changes, or equivalently, to keep a stable line of v1.x releases going for as long as possible.

Quoting @JeffBezanson in https://github.com/JuliaLang/julia/issues/23224#issuecomment-336724709:

Maybe leftward arrows should also be right-associative?

I think this is the correct answer. We should be conservative with any operator we're not sure what the behavior of it should be. We can always add them later once we've sorted it out but there's a significant chance of being stuck with unusable syntax due to mistakes like this that we can't change. Of course, this is precisely the sort of thing that femtocleaner can easily fix, but changing associativity is very much a breaking change.

I've make a small test using the operator <|, defined in the link from @schlichtanders, which transforms sum ( rand ( 100000 ) ) to `sum ∘ rand <| 1000000. And using BenchmarkTools I created a primitive example.

julia>using BenchmarkTools

# The new operator
julia> f <| x = f(x)

julia> @benchmark sum ∘ rand <| 1000000 samples=100
BenchmarkTools.Trial: 
  memory estimate:  7.63 MiB
  allocs estimate:  2
  --------------
  minimum time:     1.553 ms (0.00% GC)
  median time:      2.849 ms (0.00% GC)
  mean time:        2.495 ms (13.84% GC)
  maximum time:     4.079 ms (17.72% GC)
  --------------
  samples:          100
  evals/sample:     1

julia> @benchmark sum(rand(1000000)) samples=100
BenchmarkTools.Trial: 
  memory estimate:  7.63 MiB
  allocs estimate:  2
  --------------
  minimum time:     1.533 ms (0.00% GC)
  median time:      3.036 ms (0.00% GC)
  mean time:        2.651 ms (14.08% GC)
  maximum time:     4.250 ms (44.90% GC)
  --------------
  samples:          100
  evals/sample:     1

Using the operator with <| is a bit more elegant form my point of view. Since for you'd have to enclose the function chain and the argument separatly, e.g.

( sum ∘ rand)(100000)

And for some reason there seams to be a small performance boost with the new operator? Still wondering about the GC percentages. Thought maybe I'm missing something.

For my own nefarious reasons, I've been wondering if |> could also compose the functions before calling the result?

I've been working on a prototype implementation on my forked version. I've implemented some tests for the functionality in test/operators.jl, but the broadcasting doesn't seem to work as expected.

julia> sum ∘ sqrt .∘ rand <| 10
ERROR: MethodError: no method matching sqrt(::Array{Float64,1})
Closest candidates are:
  sqrt(::Float16) at math.jl:971
  sqrt(::Complex{Float16}) at math.jl:972
  sqrt(::BigFloat) at mpfr.jl:489
  ...
Stacktrace:
 [1] (::getfield(Base, Symbol("##57#58")){typeof(sum),typeof(sqrt)})(::Array{Float64,1}, ::Vararg{Array{Float64,1},N} where N) at ./operators.jl:985
 [2] <|(::getfield(Base, Symbol("##57#58")){getfield(Base, Symbol("##57#58")){typeof(sum),typeof(sqrt)},typeof(rand)}, ::Int64) at ./operators.jl:962

I'm on Fedora 25 an tested this with 0.6, where the following deprecation warning was prompted

julia> f <| x = f(x)
<| (generic function with 1 method)

julia> sum ∘ sqrt .∘ rand <| 10
WARNING: sqrt{T <: Number}(x::AbstractArray{T}) is deprecated, use sqrt.(x) instead.
Stacktrace:
 [1] sqrt(::Array{Float64,1}) at ./deprecated.jl:57
 [2] #55 at ./operators.jl:884 [inlined] (repeats 2 times)
 [3] <|(::Base.##55#56{Base.##55#56{Base.#sum,Base.#sqrt},Base.Random.#rand}, ::Int64) at ./REPL[1]:1
 [4] macro expansion at ./REPL.jl:97 [inlined]
 [5] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
while loading no file, in expression starting on line 0
6.619412577220985
Was this page helpful?
0 / 5 - 0 ratings