Stream: ideas

Topic: cond-like if syntax


view this post on Zulip Georges Boris (Apr 19 2023 at 12:14):

as mentioned on the "elif syntax" thread and previously on a forgotten thread :sweat_smile: - I'd like to propose a different if syntax that would use less reserved keywords and be less verbose for large if else if else if else... cases.

if
  b <= 0 ->
    "c'mon..."

  b == 1 ->
    "just one?"

  b > 5 ->
    "whoa there"

  _ ->
    "fine I guess"

we wouldn't need then and else as reserved keywords. the compiler could catch a lack of true or _ and warn the user. it feels a lot like when ... is so it would be familiar to Roc developers and there is basically no readability cost for increasing the number of cases (in comparison to if/else if)

view this post on Zulip Georges Boris (Apr 19 2023 at 12:16):

this is inspired by the cond feature of the elixir language. I find it a bit weird there because it is just another way of achieving the same you could do with if/else if.

view this post on Zulip Richard Feldman (Apr 19 2023 at 12:17):

to clarify: today this example would look like this, right?

if b <= 0 then
    "c'mon..."
else if b == 1 then
    "just one?"
else if b > 5 then
    "whoa there"
else
    "fine I guess"

view this post on Zulip Georges Boris (Apr 19 2023 at 12:20):

yeah

view this post on Zulip Georges Boris (Apr 19 2023 at 12:20):

with extra vertical space but yeah

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:21):

One of the cool things about this suggestion is that we could also change when .. is to be if .. is and further simplify the language, as in:

if
  b > a ->
    Stdout.line "b is greater than a"
  a == b ->
    Stdout.line "a and b are equal"
  _ ->
    Stdout.line "a is greater than b"

and

if word is
   "YES" ->
        Stdout.line "word is: YES"
   "NO ->
        Stdout.line "word is: NO"
   _ ->
         Stdout.line "word is not YES or NO"

view this post on Zulip Georges Boris (Apr 19 2023 at 12:24):

another advantage is that ordering does not rely on a change of if to else if - so changes there would probably be more accurate in regards to version control diffs.

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 12:29):

One downside of this is that you couldn’t have a single line if, but that might actually be good for readability

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 12:30):

I like how the conditions align

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:39):

single line if: if a > b -> "TRUE" _-> "False" could work somehow?

view this post on Zulip Richard Feldman (Apr 19 2023 at 12:41):

I don't think that would work in the general case - e.g. if foo Bar Baz -> "TRUE" - is Bar an argument to foo or part of the Bar Baz -> pattern?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:42):

maybe it could require a comma or sometthing

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:42):

if a > b -> "TRUE", _-> "False"

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:43):

that seems worse than else though

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:46):

We could live without one line if statements?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 12:49):

I would gladly give up one line if statements for the glory of clean branches in general.

view this post on Zulip Anton (Apr 19 2023 at 12:50):

I think so, I've never been a fan of one line if

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:10):

I tried this in a couple of places and it's cool when you have at least one else if, but it feels worse when you just have if/else

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:11):

smallest : Num a, Num a -> Num a
smallest = \a, b ->
    if a < b then
        a
    else
        b

smallest : Num a, Num a -> Num a
smallest = \a, b ->
    if
        a < b ->
            a
        _ ->
            b

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:12):

I find the if/then/else version much more readable

view this post on Zulip Matthias Toepp (Apr 19 2023 at 13:12):

More verbose could be:

ifTrue
  b > a ->
    Stdout.line "b is greater than a"
  a == b ->
    Stdout.line "a and b are equal"
  _ ->
    Stdout.line "a is greater than b"

and

if word is
   "YES" ->
        Stdout.line "word is: YES"
   "NO ->
        Stdout.line "word is: NO"
   _ ->
         Stdout.line "word is not YES or NO"

That underlines the difference between the two.
That would perhaps allow for better editor completion.

view this post on Zulip Anton (Apr 19 2023 at 13:19):

ifTrue feels like it really sticks out compared to the rest of the language. I think your previous proposal works well, I don't anticipate a problem for editor autocomplete because for one variant you'll be using a space and for the other a newline.

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:20):

Another downside you can see in my example is that this introduces another level of indentation

view this post on Zulip Anton (Apr 19 2023 at 13:21):

I find the if/then/else version much more readable

The short variable names in that example may create a unique worst case look

view this post on Zulip Matthias Toepp (Apr 19 2023 at 13:22):

Anton said:

ifTrue feels like it really sticks out compared to the rest of the language. I think your previous proposal works well, I don't anticipate a problem for editor autocomplete because for one variant you'll be using a space and for the other a newline.

Agreed re the wierdness of it. (Good if conflating the two is not a problem).

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:24):

Anton said:

I find the if/then/else version much more readable

The short variable names in that example may create a unique worst case look

Ok, here's another example from roc-pg:

name =
    if Set.contains reusedIndexes cmdIndex then
        Batch.reuseName cmdIndex
    else
        ""

name =
    if
        Set.contains reusedIndexes cmdIndex ->
            Batch.reuseName cmdIndex
        _ ->
            ""

view this post on Zulip Anton (Apr 19 2023 at 13:27):

It's close but I prefer the new style there

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:28):

Oh, even without an else if?

view this post on Zulip Anton (Apr 19 2023 at 13:29):

yes

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 13:29):

Ok, yeah I guess it's pretty subjective

view this post on Zulip Matthias Toepp (Apr 19 2023 at 13:36):

At the expense of super easy refactoring...If is such a short word that it doesn't indent much. It could be written inline with the first condition.

name =
    if Set.contains reusedIndexes cmdIndex ->
            Batch.reuseName cmdIndex
        _ ->
            ""

And really that would be pretty easy to refactor (without special editor assistance).

That indentation would make if .. is less distinctive (if when ..is were replaced by if..is. So with that indentaion then would we need to leave when ..is as is?

text =
   if word is
        "YES" ->
              Stdout.line "word is: YES"
        "NO ->
              Stdout.line "word is: NO"
        _ ->
         Stdout.line "word is not YES or NO"

Not sure if the two would get too confusing then.

view this post on Zulip Anton (Apr 19 2023 at 13:57):

name =
    if Set.contains reusedIndexes cmdIndex ->
            Batch.reuseName cmdIndex
        _ ->
            ""

With the _ -> not lining up with anything else this type of indentation would be unique in the language which I would try to avoid...

view this post on Zulip Matthias Toepp (Apr 19 2023 at 13:58):

it would have to line up with the word after if.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 14:00):

Personally I'm ok with all the space around if, I was just trying it out with if inline to see how it looks.

view this post on Zulip Georges Boris (Apr 19 2023 at 14:09):

inlining the first if would also create the "problem" that reordering the list of cases would require changing which has the if or not (bad for diffs)

view this post on Zulip Matthias Toepp (Apr 19 2023 at 14:11):

@Agus Zubiaga

Agus Zubiaga said:

smallest : Num a, Num a -> Num a
smallest = \a, b ->
    if a < b then
        a
    else
        b

smallest : Num a, Num a -> Num a
smallest = \a, b ->
    if
        a < b ->
            a
        _ ->
            b

I find the if/then/else version much more readable

It strikes me the same at first but maybe it's just discomfort with all the zen ( noise free code). :grinning_face_with_smiling_eyes:

I think it's quickly growing on me.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 14:28):

The proposed if syntax is basically the same as the when .. is syntax.

It fundamentally makes the language more consistent.

That makes it kind of difficult to argue with. If the conventional if..else syntax is preferable then we should re-evaluate the pattern match syntax.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 14:30):

if we desire to pursue the proposal, there's the question in my mind though how much syntactic differentiation we would want between when..is and if.

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 14:38):

I think the extra indenting will be really annoying. That is actually my biggest annoyance with when as well. In complex functions it pushes everything to the right and makes it painful to read. Means that you need to start figuring out how to pull out subfunctions much much sooner if you want readability.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 14:51):

Brendan Hansknecht said:

I think the extra indenting will be really annoying. That is actually my biggest annoyance with when as well. In complex functions it pushes everything to the right and makes it painful to read. Means that you need to start figuring out how to pull out subfunctions much much sooner if you want readability.

It's one extra line of indentation right? And an extra line of (vertical) space:

if
  b <= 0 ->
    "c'mon..."

  b == 1 ->
    "just one?"

  b > 5 ->
    "whoa there"

  _ ->
    "fine I guess"

vs (the current syntax)

if b <= 0 then
    "c'mon..."

else if  b == 1 then
    "just one?"

else if  b > 5 then
    "whoa there"

  else
    "fine I guess"

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 14:51):

As a concrete example. Code from hashing for the roc Dict:

addBytes : LowLevelHasher, List U8 -> LowLevelHasher
addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if length <= 16 then
            if length >= 4 then
                x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                b =
                    (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                    |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                { a, b, seed }
            else if length > 0 then
                { a: wyr3 list 0 length, b: 0, seed }
            else
                { a: 0, b: 0, seed }
        else if length <= 48 then
            hashBytesHelper16 seed list 0 length
        else
            hashBytesHelper48 seed seed seed list 0 length

    combineState (@LowLevelHasher { originalSeed, state }) { a: abs.a, b: abs.b, seed: abs.seed, length: Num.toU64 length }

with proposed syntax:

addBytes : LowLevelHasher, List U8 -> LowLevelHasher
addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if
            length <= 16 ->
                if
                    length >= 4 ->
                        x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                        a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                        b =
                            (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                            |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                        { a, b, seed }
                    length > 0 ->
                        { a: wyr3 list 0 length, b: 0, seed }
                    _ ->
                        { a: 0, b: 0, seed }
            length <= 48 ->
                hashBytesHelper16 seed list 0 length
            _ ->
                hashBytesHelper48 seed seed seed list 0 length

    combineState (@LowLevelHasher { originalSeed, state }) { a: abs.a, b: abs.b, seed: abs.seed, length: Num.toU64 length }

Personally, I think that already reads worse due to indenting so many lines and some conditions being far enough apart that alignment doesn't necessarily help much. This function is not even that complex. This will be a lot worse in a function that already has a few level of nesting and potentially an inline if that needs to be rewriting to multiline format.

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 14:54):

@Matthias Toepp your example is mixing indent sizes. If you are gonna use a two space indent with the new syntax, you should use a two space indent with the old syntax.

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 14:56):

As an extra note to my comment, I think when is ok with the extra indenting becuase it is less common to be nested and can often pattern match on multiple things to remove nesting. I still would prefer it not to nest so much though (don't know of a reasonable syntax to help with that though).

if on the other hand is much more likely to nest and has no good solutions for removing nesting.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:04):

@Brendan Hansknecht Re extra indentation....I guess it's True (as proposed). I guess there's no reason we couldn't eliminate the indentaion:
We could change your example:

addBytes : LowLevelHasher, List U8 -> LowLevelHasher
addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if
            length <= 16 ->
                if
                    length >= 4 ->
                        x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                        a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                        b =
                            (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                            |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                        { a, b, seed }
                    length > 0 ->
                        { a: wyr3 list 0 length, b: 0, seed }
                    _ ->
                        { a: 0, b: 0, seed }
            length <= 48 ->
                hashBytesHelper16 seed list 0 length
            _ ->
                hashBytesHelper48 seed seed seed list 0 length

    combineState (@LowLevelHasher { originalSeed, state }) { a: abs.a, b: abs.b, seed: abs.seed, length: Num.toU64 length }

to:

addBytes : LowLevelHasher, List U8 -> LowLevelHasher
addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if
        length <= 16 ->
            if
            length >= 4 ->
                x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                b =
                    (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                    |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                { a, b, seed }
            length > 0 ->
                { a: wyr3 list 0 length, b: 0, seed }
            _ ->
                { a: 0, b: 0, seed }
        length <= 48 ->
            hashBytesHelper16 seed list 0 length
        _ ->
            hashBytesHelper48 seed seed seed list 0 length

    combineState (@LowLevelHasher { originalSeed, state }) { a: abs.a, b: abs.b, seed: abs.seed, length: Num.toU64 length }

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:07):

A similar thing could be done with when..is (shown as if..is)

text =
   if word is
   "YES" ->
        Stdout.line "word is: YES"
   "NO ->
        Stdout.line "word is: NO"
   _ ->
         Stdout.line "word is not YES or NO"

view this post on Zulip Anton (Apr 19 2023 at 15:11):

I actually prefer Brendan's "with proposed syntax:" example

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:13):

@Anton Why? It does involve more indentation.

view this post on Zulip Anton (Apr 19 2023 at 15:17):

putting the length <= 16 -> at the same column as the if seems very atypical, I don't think I've seen anything like it in any programming language. The extra indentation makes it less busy.

view this post on Zulip Anton (Apr 19 2023 at 15:18):

I also generally like to pull functions out when things get too involved / deeply nested

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:19):

@anton. Isn't that basically what being done with if..else to get the indentation that @Brendan Hansknecht prefers.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:21):

i.e. the natural indentation of an if statement is elided. I.e. normal if..else statements don't follow a rule of immediate indentation.

view this post on Zulip Anton (Apr 19 2023 at 15:23):

I'm sorry, I can't quite follow your statement, can you explain in more detail?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:24):

The traditional form of an if statement doesn't have every line that follows the start of the if indented.

view this post on Zulip Anton (Apr 19 2023 at 15:27):

Yes, I like the "next inside thing" to be indented

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:27):

I think the proposed suggestion is to start an if with an initial indention and then indent further.

view this post on Zulip Anton (Apr 19 2023 at 15:28):

yes that's how I like it :)

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:28):

Anton said:

Yes, I like the "next inside thing" to be indented

Since that's not how an if else statement works there's necessarily an extra level of indentation then right?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:29):

So someone could validly argue that the proposed if syntax causes extra indentation, and that that's a bad thing.

view this post on Zulip Anton (Apr 19 2023 at 15:31):

I don't mind the extra indentation in this case:

abs =
        if
            length <= 16 ->
                if
                    length >= 4 ->
                        x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                        a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                        b =
                            (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                            |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                        { a, b, seed }
                    length > 0 ->
                        { a: wyr3 list 0 length, b: 0, seed }
                    _ ->
                        { a: 0, b: 0, seed }
            length <= 48 ->
                hashBytesHelper16 seed list 0 length
            _ ->
                hashBytesHelper48 seed seed seed list 0 length

    combineState (@LowLevelHasher { originalSeed, state }) { a: abs.a, b: abs.b, seed: abs.seed, length: Num.toU64 length }

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:34):

@Anton Either way is fine I guess, but I don't have any trouble parsing this:

text =
   if word is
   "YES" ->
        Stdout.line "word is: YES"
   "NO ->
        Stdout.line "word is: NO"
   _ ->
         Stdout.line "word is not YES or NO"

I think it might look a bit more grounded, and practically it does remove one level of extra indentaion.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:40):

That particular example I gave above is pretty difficult to misconstrue isn't it?

view this post on Zulip Anton (Apr 19 2023 at 15:42):

I don't have any problems parsing it either and I bet I could get used to it easily. It's just seems so different than usual

view this post on Zulip Anton (Apr 19 2023 at 15:45):

If I'd seen it before I'd probably say it's the best way :)

view this post on Zulip Anton (Apr 19 2023 at 15:53):

I'm curious what others think

view this post on Zulip Matthias Toepp (Apr 19 2023 at 15:54):

Honest question...why does it seem more ok for if .. else not to be written as:

if b <= 0 then
       "c'mon..."
    else if b == 1 then
                         "just one?"
                    else if b > 5 then
                                            "whoa there"
                                      else
                                            "fine I guess"

Maybe because there is a keyword prefixing it?...makes it seem normal?

view this post on Zulip Anton (Apr 19 2023 at 15:58):

That indentation looks wild, "more ok" compared to what?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:01):

It seems like what you want to do is indent and then indent again, but that's not what if..else does so I'm trying to understand why it's acceptable for the if and else to all line up on the left but for the new if syntax not to.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:03):

Maybe it doesn't work normally because putting the if directly in line with the cases assumes that you are at a new level of indentation and nothing can follow at that level, that probably makes it wierd? (I'm still thinking about this:)

text =
   if word is
   "YES" ->
        Stdout.line "word is: YES"
   "NO ->
        Stdout.line "word is: NO"
   _ ->
         Stdout.line "word is not YES or NO"

view this post on Zulip Anton (Apr 19 2023 at 16:05):

"because putting the if directly in line with the cases assumes that you are at a new level of indentation and nothing can follow at that level, that probably makes it weird" yes that was my feeling indeed

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:07):

I'm trying to find an example where that wouldn't work.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:16):

Assuming that wraping the conditions in the elsekeyword permits the eliding of indentation...that probably brings us to either accepting the extra indentation or using a prefix character (like fsharp uses the pipe) or we're back to having a word prefix for the branches.

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 16:26):

@Anton i have a few issue with the extra indentation. For example, in the code I write above, i would not feel safe pulling things into an extra function to avoid indentation (at least not without an always inline attribute being added to roc). Those branches are set up in a very specific way for performance.

That said, i also think, a lot of the time, more context is very important (and the main reason to avoid sub functions). So pulling into a lot of smaller function with only one use can really hurt readability. If you think a function should roughly be at most 4 indents deep (arbitrary number, just pretend this is when you would likely pull out a sub function), with the new syntax, you will be making new functions when you have half the amount of nesting as the old syntax. This means more cases of split up control flow where you can't see the full context and better hope you have a good name for the subfunctions that is understandable to others.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:28):

fsharp has a prefix character and doesn't indent after the match keyword:

let rangeTest testValue mid size =
    match testValue with
    | var1 when var1 >= mid - size/2 && var1 <= mid + size/2 -> printfn "The test value is in range."
    | _ -> printfn "The test value is out of range."

view this post on Zulip Georges Boris (Apr 19 2023 at 16:33):

addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if
            length <= 16 ->
                if
                    length >= 4 ->
                        x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                        a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                        b =
                            (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                            |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                        { a, b, seed }

                    length > 0 ->
                        { a: wyr3 list 0 length, b: 0, seed }

                    _ ->
                        { a: 0, b: 0, seed }

            length <= 48 ->
                hashBytesHelper16 seed list 0 length

            _ ->
                hashBytesHelper48 seed seed seed list 0 length

view this post on Zulip Georges Boris (Apr 19 2023 at 16:34):

the example above with proper vertical spacing

view this post on Zulip Georges Boris (Apr 19 2023 at 16:34):

I think it also looks a bit weird due to the immediate nested if statement... so trying to refactor:

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:35):

@Georges Boris
How about:

reaction =
  if
  | b <= 0 ->
    "c'mon..."

  | b == 1 ->
    "just one?"

  | b > 5 ->
    "whoa there"

  | _ ->
    "fine I guess"

To reduce the amount of indentation needed (to avert the criticism that this causes too much indentation)?

view this post on Zulip Georges Boris (Apr 19 2023 at 16:36):

addBytes = \@LowLevelHasher { originalSeed, state }, list ->
    length = List.len list
    seed = Num.bitwiseXor originalSeed wyp0
    abs =
        if
            length <= 16 && length >= 4 ->
                        x = Num.shiftRightZfBy length 3 |> Num.shiftLeftBy 2
                        a = Num.bitwiseOr (wyr4 list 0 |> Num.shiftLeftBy 32) (wyr4 list x)
                        b =
                            (wyr4 list (Num.subWrap length 4) |> Num.shiftLeftBy 32)
                            |> Num.bitwiseOr (wyr4 list (Num.subWrap length 4 |> Num.subWrap x))

                        { a, b, seed }

            length > 0 && length >= 16 ->
                        { a: wyr3 list 0 length, b: 0, seed }

            length >= 16 ->
                        { a: 0, b: 0, seed }

            length <= 48 ->
                hashBytesHelper16 seed list 0 length

            _ ->
                hashBytesHelper48 seed seed seed list 0 length

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 16:36):

Refactoring is wrong in this case

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 16:36):

It is that way specifically for branch prediction and performance

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 16:37):

So just pretend they are unique branches that don't make sense to merge.

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 16:37):

Also, i like the idea of a precursor character to avoid indenting

view this post on Zulip Kiryl Dziamura (Apr 19 2023 at 16:38):

speaking of the match - what is the fundamental difference between pattern matching and if-else? maybe it's a bit out of the topic - but when I learned about pattern matching - my first question was "why do I need if-else now?"
they seem to do almost the same but have different wording. I didn't think about it much though

view this post on Zulip Ayaz Hafiz (Apr 19 2023 at 16:40):

There is no fundamental difference, everything you can do with if you can do with a when match, if just optimizes space for the exactly-2-branches case

view this post on Zulip Ayaz Hafiz (Apr 19 2023 at 16:41):

personally I feel like I write conditions like

prefix = if startOfLine then "header > " else ""

"\(prefix)(content)"

all the time, I don't think splitting conditions like that over multiple lines or indenting helps readability

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:41):

@Kiryl Dziamura when..if (roc's) matching could be written as when True is followed by the conditional branches to produce an if-else system.

view this post on Zulip Georges Boris (Apr 19 2023 at 16:41):

@Kiryl Dziamura we've discussed that previously and tried it out different ways but basically the if ignores a particular matched value and can match on different expressions that are independent of each otherm so basically:

when a is
  _, 1 > 2 -> false
  _, k == "f" -> true

we're ignoring the a and just using the guards.

view this post on Zulip Georges Boris (Apr 19 2023 at 16:43):

I'm not a fan of the prefix character fwiw - that syntax is usually used for pattern match as a whole, right? and imo is quite verbose... but if it should be used for if then it should probably be used for when

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:44):

Georges Boris said:

I'm not a fan of the prefix character fwiw - that syntax is usually used for pattern match as a whole, right? and imo is quite verbose... but if it should be used for if then it should probably be used for when

in that case it would reduce indentation with both
I'm not seeing another way of competing with the traditional if else in terms of indentaion.

view this post on Zulip Georges Boris (Apr 19 2023 at 16:49):

we can use 2-space indents if horizontal space is a priority :troll:

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:50):

Are 4 spaces standard now?

view this post on Zulip Matthias Toepp (Apr 19 2023 at 16:51):

or 3?

view this post on Zulip Georges Boris (Apr 19 2023 at 16:58):

4 spaces. similar to Elm.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 17:14):

So it seems like we can have the proposed syntax but we have to accept extra indentation. (not sure how to decide that.).
OR
Have a prefix character on branches.
OR
Go back to if else
OR ..?

view this post on Zulip Richard Feldman (Apr 19 2023 at 17:19):

I'm definitely not sold on this being a good use of weirdness budget

view this post on Zulip Richard Feldman (Apr 19 2023 at 17:20):

if / then / else is not weird to anyone with a background in any mainstream language, but the proposed syntax is...and I'm just not seeing the benefits justifying that

view this post on Zulip Richard Feldman (Apr 19 2023 at 17:20):

supposing it is better, it's not by much

view this post on Zulip Folkert de Vries (Apr 19 2023 at 17:26):

note that

when a is
  _ if 1 > 2 -> false
  _ if k == "f" -> true

is already valid syntax (it will need a default branch though). I really don't see the problem that is being solved here though.

view this post on Zulip Folkert de Vries (Apr 19 2023 at 17:27):

(aside: you may see the above in some haskell code, because a pattern match strictly evaluates its scrutinee)

view this post on Zulip Matthias Toepp (Apr 19 2023 at 17:28):

On the other hand there doesn't seem to be a real justification for having a completely different syntax for if else vs when is it's like they come from two different worlds by syntax even though they are intimately related. And the only reason we can't be more consistent and clear and elegant is because that's the way it's always been done and we can't figure out how to avoid increasing indentation without adding a prefix character. We already basically have this syntax, it's just a question of whether we want two disconnected syntaxes, one for if else and one for when is.

view this post on Zulip Matthias Toepp (Apr 19 2023 at 17:35):

the proposed syntax puts the conditions front and center with minimal noise. The problem is syntactic noise. And we can see that it (the noise) doesn't exist in an existing structure (the when ..is) which is basically a superset of if else (redundancy).

view this post on Zulip Folkert de Vries (Apr 19 2023 at 17:37):

yeah I'm fine with that redundancy

view this post on Zulip Matthias Toepp (Apr 19 2023 at 17:44):

Does that mean this issue is decided or how does this work?

view this post on Zulip Agus Zubiaga (Apr 19 2023 at 17:47):

The way I see it, the proposed syntax has these advantages:

And it has these downsides:

At least for me, that justifies having different syntaxes for if and when..is.

view this post on Zulip Anton (Apr 19 2023 at 17:50):

This seems well-suited to using an editor plugin to display it how you prefer :)

view this post on Zulip Matthias Toepp (Apr 19 2023 at 17:58):

I appreciate that there are some others out there with my leanings. I would be very happy for something to happen with this proposal... My initial hope today was to suggest a way to reduce the noisiness of else if by changing that to elif. I really liked the essence of this proposal. But if the proposal of this thread is a no-go then I hope the idea of elif will be considered: https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/elif.20syntax

view this post on Zulip Georges Boris (Apr 19 2023 at 21:24):

Agus Zubiaga said:

The way I see it, the proposed syntax has these advantages:

And it has these downsides:

At least for me, that justifies having different syntaxes for if and when..is.

advantages:

as for the downsides:

when a is
  Good -> "good"
  Bad -> "bad"

and

when a is
  Good ->
    "good"

  Bad ->
    "bad"

this adds up a lot when mapping values.

view this post on Zulip Richard Feldman (Apr 19 2023 at 21:41):

I've liked single-line if and the formatter in Roc supports them (I explicitly wanted to support them because I missed them in Elm!)

view this post on Zulip Brendan Hansknecht (Apr 19 2023 at 22:15):

This is definitely an interesting debate. I find the weirdness budget a complex topic. I do think that proposed syntax in a lot of cases could be much nicer.


Last updated: Jun 16 2026 at 16:19 UTC