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:
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.
then is Ruby which has a ranking of 1% on the PYPL PopularitY of Programming Language Index and a ranking of 0.66% on TIOBE.Makes roc easier to learn if you have experience with a popular programming language.
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.
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).
Simplifies Roc. One less keyword. There seems to be a strong preference to avoid keywords in roc when possible.
Less characters for the compiler to parse. (12 less characters in the sample code compared to the existing syntax.)
If when..is is changed to match () for consistency, then another keyword is eliminated.
what would a multiline condition look like? e.g. not x < 10 but something so long it spans multiple lines
#5 means then would become available in userspace, which could be useful
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:
@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"
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.
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"
@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"
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:
one argument for then is that it has symmetry with when ... is
of course, could also change that to when (...)
but I think when ... is reads nicely, especially for people who are new to ML-family pattern matching
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).
...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).
size =
match (x)
Small ->
"small"
Medium ->
"medium"
Large ->
"large"
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.
@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.
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)
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