Infix operators - lower precedence than |> and <|?


#1

Hi!

I think infix operators with lower precedence than |> and <| could be useful:

Case 1:

Operator => is pretty useful for creating tuples with two values - some examples:

  1. Example from http://package.elm-lang.org/packages/NoRedInk/rocket-update/1.0.0
button [ style [ "display" => "none" ] ] [ text "invisible!" ]
  1. Example from http://package.elm-lang.org/packages/NoRedInk/rocket-update/1.0.0
SendOtherRequest ->
    model
        |> doSomethingToModel
        |> doSomethingElseToModel
        => [ Http.send someOtherRequest ]
  1. Example
Json.Encode.object
    [ "states" => projectData.states |> statesEncoder
    , "something" => ...

Problem:

There is a bug in example 3 - "states" => projectData.states |> statesEncoder throws

“Conflicting associativity for binary operators (=>, |>). Consider adding parentheses to disambiguate.”

Packages with operator =>:


Case 2:

I often have to rewrite <| something to ( something ) due to conflicting operators <| and |>.

1. Example without pipeline

SetTitle <| toString aNumber 

2. Example with pipeline

SetTitle (aNumber |> toString) 

Problem:

I thought I can remove extra parentheses - just implement an operator <|| (something like <| on steroids) and write:

SetTitle <|| aNumber |> toString

But set precedence with infix -1 <|| is not possible. (See http://faq.elm-community.org/operators.html and http://elm-lang.org/docs/syntax)


Case 3:

Precedence of the operator ! is a little bit counter-intuitive - I think it should have been processed after pipelines. (Not only mine experience + https://github.com/elm-lang/core/issues/638)


Conclusion

I agree that infix operators shouldn’t be used very often but I think some cases exist where they can make code more readable and simpler for refactoring. But with limited precedence settings some of these cases are not possible.

Thank You for feedback!


#2

First thought reading through this: Wow, that’s a nicely structured writeup with some good examples :clap:

I have mixed feelings here. I can totally see why people might want this. Personally though, I guess pipelined sub-expressions are too much cognitive overhead for my taste. I generally prefer to write inline single pipes as function calls. For inline multi-pipe sub-expressions, I prefer to extract them to their own functions, leading to the same result.

Pipes are awesome but I wonder if the need for this requested feature points to them being used in a context they are less suited too :thinking: It definitely points to wanting to do more inline.

Reading other people’s code, I notice that I have a much lower tolerance for inlined sub-expressions than a lot of the rest of the community so that definitely informs my opinions here :laughing:


#3

Yeah, I’m backend programmer in my day-job, so I have to use OOP langs without pipes - but I’ve found out that for me:

  • It’s easier to follow data flow rather then function calls
  • It’s simpler to add |> Debug.log "foo" at the end of pipe then wrap whole expression with Debug.log
  • See docs for elm-test http://package.elm-lang.org/packages/elm-community/elm-test/latest - comment in the first example: -- Expect.equal is designed to be used in pipeline style, like this.
  • I’m used to write something.toString() so something |> toString seems more natural
  • The biggest cognitive overhead are parentheses (e.g. callback hell from Javascript dark times) - I want to remove them whenever possible
  • It’s more natural to write pipes than function calls because I don’t have to “switch context” between writing single-line pipes and multi-line pipes ; Also it’s easier to rewrite single-line pipe to multi-line one if necessary

Could you send link to some non-trivial code that you’ve written? (I just want to see some demostration of those principals you described in your answer)

Thanks!


#4

I’ve heard that ability to define custom infix operators will be removed in 0.19 entirely.


#5

Good point. I also came to Elm from OOP (Ruby) and pipes did feel closer to the dot notation I was familiar with.

To be clear, I’m not against pipelines in general (they’re great!) or even single-pipe chains. This is more about inline sub-expressions than pipelines :slightly_smiling_face:

The OOP equivalent would be extracting long method chains or compound boolean expressions to their own methods.

I built two games for recent Elm gamejams. They should qualify as open-source non-trivial Elm code:


#6

Where did you hear that custom infix operators will be removed in 0.19?

Edit: Found this https://www.reddit.com/r/elm/comments/81bo14/do_we_need_to_move_away_from_elm/


#7

Was also discussed here.


#8

The quoted code is very confusing.

In any case, Elm has a history of getting rid of facilities that, altho might look nice in the beginning, lead to confusion and less obvious code.

User defined operators fit in this category. ! and => will go away as they have a clear history of generating confusion. I have used them both to great extent in various projects and altho I appreciate their cleverness, I think their removal will improve the code people write. One less footgun.

As a famous designer said: “Weniger, aber besser” (Less but better).


#9

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.