Stream: ideas

Topic: eliminate `then` keyword


view this post on Zulip Matthias Toepp (Apr 29 2023 at 20:39):

The suggestion is to eliminate the then keyword from roc.

This would result in:

if (x < 10) "small number" else "large number"

if (x < 10)
    "less than ten"
else if (x < 100)
    "less than one hundred"
else if (x < 1000)
   "less than one thousand"
else
    "large number"

compared to the existing syntax:

if x < 10 then "small number" else "large number"

if x < 10 then
    "less than ten"
else if x < 100 then
    "less than one hundred"
else if x < 1000 then
   "less than one thousand"
else
    "large number"

Advantages:

  1. Reduces the feeling of roc's strangeness. The proposed syntax is much more conventional. Most programmers will not be familiar with the use of the then keyword.

  2. Makes roc easier to learn if you have experience with a popular programming language.

  3. Removes syntax noise. then surrounds the conditions in keywords. In mult-line syntax, the conditions should be exposed as much as possible, as they are the points of interest.

  4. The conventional use of parenthesis in the proposed syntax serves to emphasize the conditions (which, again, should be the focus). This emphasis facilitates vertical scanning of the conditions, (as they stand out due to the brackets).

  5. Simplifies Roc. One less keyword. There seems to be a strong preference to avoid keywords in roc when possible.

  6. Less characters for the compiler to parse. (12 less characters in the sample code compared to the existing syntax.)

  7. If when..is is changed to match () for consistency, then another keyword is eliminated.

view this post on Zulip Richard Feldman (Apr 29 2023 at 20:41):

what would a multiline condition look like? e.g. not x < 10 but something so long it spans multiple lines

view this post on Zulip Richard Feldman (Apr 29 2023 at 20:42):

#5 means then would become available in userspace, which could be useful

view this post on Zulip Matthias Toepp (Apr 29 2023 at 20:46):

Yes, then is nice to separate a long condition...maybe it would be a good thing to factor out a large condition like that anyway? :blush:

view this post on Zulip Matthias Toepp (Apr 29 2023 at 20:52):

@Richard Feldman
How about?...

if (x <10 && longConditionOne && longConditionTwo && longConditionThree
&& longConditionFour && ConditionFive)
    "less than ten"
else if (x < 100)
    "less than one hundred"
else if (x < 1000)
   "less than one thousand"
else
    "large number"

view this post on Zulip Nulldata (Apr 29 2023 at 21:02):

While I do like the general idea of having few keywords, I personally prefer keeping then.
While it might not be very conventional in languages with C-like syntax, it is very conventional in
the ML family of functional languages (like SML, Haskell, OCaml, F# and of course Elm). And considering how foreign Roc already looks compared to the C-like syntax that some people are used to, I don't think it would have a big learning impact. Though that is of course just conjecture.

Though doing this only for then would make the syntax inconsistent. I guess you'd have to changewhen x is to when (x) too.

view this post on Zulip Matthias Toepp (Apr 29 2023 at 21:03):

How about?...

if (x <10 && longConditionOne && longConditionTwo && longConditionThree
    && longConditionFour && ConditionFive
    )
    "less than ten"
else if (x < 100)
    "less than one hundred"
else if (x < 1000)
   "less than one thousand"
else
    "large number"

view this post on Zulip Matthias Toepp (Apr 29 2023 at 21:04):

@Richard Feldman
How about?...

if (x <10 && longConditionOne && longConditionTwo && longConditionThree
    && longConditionFour && ConditionFive)

    "less than ten"
else if (x < 100)
    "less than one hundred"
else if (x < 1000)
   "less than one thousand"
else
    "large number"

view this post on Zulip Richard Feldman (Apr 29 2023 at 21:16):

While it might not be very conventional in languages with C-like syntax, it is very conventional in the ML family of functional languages

I think syntactic familiarity to people coming from the ML family of languages is nice when it works out, but it shouldn't be a big priority :big_smile:

view this post on Zulip Richard Feldman (Apr 29 2023 at 21:20):

one argument for then is that it has symmetry with when ... is

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

of course, could also change that to when (...)

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

but I think when ... is reads nicely, especially for people who are new to ML-family pattern matching

view this post on Zulip Matthias Toepp (Apr 29 2023 at 21:36):

Richard Feldman said:

of course, could also change that to when (...)

how about match () which I think also works (used in Rust, F# and Ocaml I believe).

view this post on Zulip Matthias Toepp (Apr 29 2023 at 21:37):

...that would then eliminate 2 key words (then and is).
And I think that would also feel more conventional (and obviously natural for people from Rust, F#, and Ocaml).

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

size =
    match (x)
        Small ->
             "small"
        Medium ->
             "medium"
        Large ->
             "large"

view this post on Zulip Brendan Hansknecht (Apr 30 2023 at 15:27):

I think either of these options would both essentially read equally well. The small exception being single variable conditionals. match (x) will read slightly worse than when x is in my opinion. Just cause the unnecessary parens. Parens also have the minor annoyance of being easy to mess up and minorly more annoying to edit. That is part of the reason I love using |> in roc.

Editing parens or adding a wrapping function is annoying in this :

await (someFunc (someOtherFunc {}) "abc" )

# lets wrap someOtherFunc with another transformation:
await (someFunc (wrapper (someOtherFunc {}) 17) "abc" )

I just find that annoying to write and edit.
vs:

someOtherFunc {}
|> someFunc "abc"
|> await

# lets wrap someOtherFunc with another transformation:
someOtherFunc {}
|> wrapper 17
|> someFunc "abc"
|> await

This is all only tangentially related, but I do think it is something to consider. Just adds more parens to any conditional and can make editing more annoying, but I think it has less of an effect for conditionals than arbitrary function calls.

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

@Brendan Hansknecht
I take your point.

re: "tangentially related"...I don't even think the when..is syntax would need to change to be consistent with this proposal...the whole layout of that decision structure is so completely different from if that I'm not sure that changing one requires changing the other.

view this post on Zulip Matthias Toepp (May 01 2023 at 01:07):

if we did want if and when to be more similar then we could also do something like what kotlin has done:
From https://learnxinyminutes.com/docs/kotlin/

    "if" can be used as an expression that returns a value.
    For this reason the ternary ?: operator is not needed in Kotlin.
    */
    val num = 5
    val message = if (num % 2 == 0) "even" else "odd"
    println("$num is $message") // => 5 is odd

    // "when" can be used as an alternative to "if-else if" chains.
    val i = 10
    when {
        i < 7 -> println("first block")
        fooString.startsWith("hello") -> println("second block")
        else -> println("else block")
    }

    // "when" can be used with an argument.
    when (i) {
        0, 21 -> println("0 or 21")
        in 1..20 -> println("in the range 1 to 20")
        else -> println("none of the above")
    }

    // "when" can be used as a function that returns a value.
    var result = when (i) {
        0, 21 -> "0 or 21"
        in 1..20 -> "in the range 1 to 20"
        else -> "none of the above"
    }
    println(result)

view this post on Zulip Matthias Toepp (May 01 2023 at 01:12):

And I've suggested going in that direction...

https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/harmonize.20decision.20structures.


Last updated: Jun 16 2026 at 16:19 UTC