Summary:
This proposal intends to make roc simpler, more powerful, more readable, more consistent, with enhanced diff and refactorability.
The idea is to upgrade roc's decision structures:
Replace the current single-line if with single-line pattern matching, which has a more powerful superset of functionality.
Introduce a boolean branching structure with when..is-like layout to take the place of our current multi-line if, then, else.
Examples of the syntax with different suggested options for names are shown in posts below.
Advantages:
This proposal simplifies roc. The else and then keywords are eliminated.
The proposed multiline branching syntax is proposed for its own advantages, however it seems to require less syntactic sugar given that if then else is implemented in terms of pattern matching (as I'm told). The proposed syntax more closely resembles the current pattern matching syntax and is less of a special case in terms of indentation.
This proposal makes roc more powerful. Single line pattern matching is more powerful then single line if then else. Single line pattern matching can successfully provide a superset of the functionality of one-line boolean branching. If we can have this then why pass on it? If we are going to have one line pattern matching then having a one line if becomes redundant as pattern matching is able to effectively express the equivalent of a single line if.
This makes roc more readable by eliminating unnecessary boilerplate/syntactic noise. It provides a more elegant multi-line boolean branching structure which follows the layout of the existing when..is. That means it doesn't obscure conditions with three keywords as we currently have with else if x then.
In other words, this proposal addresses what Python and F# address with elif, Kotlin with when, Elixir and Lisp with cond and Haskell with multiway if (and, at the same time the proposal simplifies and increases the power of the language.)
Roc also becomes more readable as the proposed multi-line branching structure enables the horizontal alignment of conditions, for enhanced vertical scanning.
This proposal provides the desired (but unnecessary) equivalent of single line if. Single-line pattern matching is arguably unusual when used as an if statement while at the same time it is clearly readable and easily understandable even to someone who has never read roc. It is just single line pattern matching with syntax consistent with the multi-line pattern matching syntax.
Since single line boolean branching and pattern matching are unnecessary (one can use mult-line syntax) there is not really a need to teach/learn "single-line branching on bools or general single-line pattern-matching".
Given that single line pattern matching is highly consistent with multi-line pattern matching, and clearly understandable even when used as a one line if statement, there is no real problem if one comes across it without having had an introduction to the "one line if" syntax.
It provides enhanced diff.
else if with elif, el, ef) if then else along side a muli-line boolean when-like structure.I do realize that roc uses Bool.true and Bool.false but that seems like an undesirable feature in itself. Could we define True = Bool.true?
roc used to have True and False. The issue is that it either had to be a built-in language type or would have some unintuitive issues due to how tag unions work. We chose to change to Bool.true/false instead of making it a special built-in type.
If you define bool directly as the non-opaque tag Bool: [ True, False ], you have the issue that it can have new tags merged into it. So you can end up with a [ True, False, SomethingElse ]. Pretty easily.
To avoid that, we made Bool opaque. Thus, you need to use the re-exported Bool.true
So far, the raw constant version of true and false are used infrequently enough that, though people find it a little weird, it tends to not really be an issue.
Generally you don't compare to true or false. Just use the values in a conditional, so they aren't needed explicitly.
Wouldn't it be possible to have a keyword True that shadows the tag and re-directs to Bool.true?
...or something like that.
I guess, that could be done. Though then no other tag could contain True.
right
Maybe not bad, but a whole separate discussion.
As in first you probably would want a proposal on that feature then you would want to come back to something like this.
I think not having true/false keywords also encourages people to use tags which is generally a better way to model things.
There's a talk about this: https://www.youtube.com/watch?v=NNKm97vihKc
Well I'm fine with that and I think in haskell True and False are tags. But I hear that they would be extendable in roc and that would cause problems.
Interesting and unfortunate.
size = if x > 5 is (True -> "greater") (False -> "smaller")
this is an interesting syntax idea for single-line pattern matches I haven't seen before - maybe it's worth a separate discussion? (e.g. current when ... is has no single-line form)
incidentally, the idea of "what if we always pattern matched on booleans" has been discussed in Elm Discourse
I updated this and made a more complete case for it in the initial two posts of this thread.
Richard Feldman said:
size = if x > 5 is (True -> "greater") (False -> "smaller")this is an interesting syntax idea for single-line pattern matches I haven't seen before - maybe it's worth a separate discussion? (e.g. current
when...ishas no single-line form)
Sure! Great! I'll rename this thread from "pattern matching if" to "1 line pattern match + when..is-like bool structure" and I'll start a new thread called "single-line pattern matching":
https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/single.20line.20pattern.20matching
The names of the structures are not very important to me.
The naming options that seem obvious to me are:
Naming scheme 1.
when..is (as existing)condsize =
when x is
Small ->
"small"
Medium ->
"medium"
_ ->
"large"
val = when res is (Ok v -> v) (_ -> crash "reason")
size = when x > 5 is (True -> "greater") (False -> "smaller")
size =
cond
y < 10 ->
"small"
y < 100 ->
"medium"
_ ->
"large"
Naming scheme 2.
when..is (as existing)ifsize =
when x is
Small ->
"small"
Medium ->
"medium"
_ ->
"large"
val = when res is (Ok v -> v) (_ -> crash "reason")
size = when x > 5 is (True -> "greater") (False -> "smaller")
size =
if
y < 10 ->
"small"
y < 100 ->
"medium"
_ ->
"large"
I have a preference for a word like cond for multi-line bool branching compared to if as it looks a bit more substantial/robust (less wispy), but the names are not very important to me.
If we are to go with a proposal like this and accept that we are essentially getting rid of if as it currently exists, I would suggest switching fully to when for both. So when instead of cond. Though that is just a naming suggestion.
As for the rest, single line is a tad verbose, but not that bad. Of course, it depends on being able to use True, gets noisy if you have to use Bool.true. at least you can use _ -> for the false case.
It also would enable things like this, which is kinda nice:
when res is (Ok v -> v) (_ -> crash "reason")
Basically an inline equivalent to .expect or .unwrap in Rust. Though probably would be best to just create the helper function: (EDIT: actually, I change my mind. I think inline is best because it exposes the fact that crash could be called. That is important info)
expect res "reason"
I think overall, it is nice and consistent.
I think the big question is if we are ok with making the language feel stranger to new users. It may hurt adoption due to being jarring in syntax. So i think it is mostly a question of weirdness budget and expectations of people thinking about migrating to the language.
Cause yeah, i think weirdness and minor verbosity are really the main drawbacks, but i think it would be trivial for people who decide to use roc to get used to.
Just may reduce how many people decide to try roc when they look at it and basic if statements don't exist or have a weird syntax.
Would it be valid to write without the additional newline?
size =
when x is
Small -> "small"
Medium -> "medium"
_ -> "large"
size = when x > 5 is (True -> "greater") (False -> "smaller")
It is currently, so I would assume that feature stays.
I don't see myself using this one-line but imo it is a syntax that makes sense so :shrug:♂️👌
Brendan Hansknecht said:
Cause yeah, i think weirdness and minor verbosity are really the main drawbacks, but i think it would be trivial for people who decide to use roc to get used to.
@Brendan Hansknecht & @Georges Boris
As far as I'm concerned I would be delighted if this proposal was accepted but the language was further simplified so that the single line was dropped all together but I believe RF has said that he missed a one line 'if' in elm...
I attempted to at least partially address the unusual nature of the one line if in the second post of the thread:
Since single line boolean branching and pattern matching are unnecessary (one can use mult-line syntax) there is not really a need to teach/learn "single-line branching on bools or general single-line pattern-matching".
Given that single line pattern matching is highly consistent with multi-line pattern matching, and clearly understandable even when used as a one line if statement, there is no real problem if one comes across it without having had an introduction to the "one line if" syntax.
The fact that this would leave us without a more "normal" one line if is perhaps a good reason to name the multi-line if :if rather than cond even though I prefer cond or when because they look less wispy.
@Brendan Hansknecht
switching fully to
whenfor both. Sowheninstead ofcond.
On the other hand, choosing when really kind of suggests why we don't have a regular if, it's because we have the more powerful when i.e pattern matching.
However, I didn't list that because I believe @Richard Feldman prefers not to have that. Given that when would be very light sugar over when is it seems more than acceptable to me, but I must be overlooking some of the disadvantages of doing that. RF refers to it as "making the grammar of the language larger" and refers to the impact on newcomers.
Since @Brendan Hansknecht mentioned it...
(I believe R.F. opposes this as making the grammar of the language larger)
Naming scheme 3.
when..is (as existing)whensize =
when x is
Small ->
"small"
Medium ->
"medium"
_ ->
"large"
val = when res is (Ok v -> v) (_ -> crash "reason")
size = when x > 5 is (True -> "greater") (False -> "smaller")
size =
when
y < 10 ->
"small"
y < 100 ->
"medium"
_ ->
"large"
I'm not sure if that naming generates actual confusion but it might at least generate fear of confusion for newcomers
That would be my preferred naming if the one line syntax was eliminated all together. The naming is not the most important thing though for me. I'd take if when cond... I even played with calling the pattern match if earlier. It looked/worked surprisingly good...
Naming scheme 4.
if..is whensize =
if x is
Small ->
"small"
Medium ->
"medium"
_ ->
"large"
val = if res is (Ok v -> v) (_ -> crash "reason")
size = if x > 5 is (True -> "greater") (False -> "smaller")
size =
when
y < 10 ->
"small"
y < 100 ->
"medium"
_ ->
"large"
Something about that naming makes me very happy :smile:
With that naming: "we don't have (one line) if" becomes "we have if and its more powerful !" (it can do boolean branching and pattern matching)...plus that gives us "Kotlin's when".
I think it just works. I guess because it reads sufficiently like english.
That naming might require pattern match guards to be renamed.
@Richard Feldman
Thanks for being so patient and generous about us exploring the whole branching thing. I really do appreciate that its more important for you to be happy with the language then me, even though that doesn't necessarily come across with my persistence on this issue. Ultimately it really does come from my appreciation for what you have built with roc and wanting it to be even better. I would just hate for roc to be outdone by Kotlin in terms of having its when!
I do also appreciate that what clearly seems better to me won't necessarily seem sufficiently better for you, or even what is better for us all could be too progressive and cause people to reject roc. I know that my biggest regret would have been that I had not tried to make the case to improve roc in this way, not that I hadn't succeeded. Thanks for letting me have the space to attempt to develop and make that case!
I think this clearly has reached a fundamental proposal. Each of the recent variations are the same except for naming (naming can easily change/be decided later). This proposal is bolder in that it completely removes the current if then else structure in order to make the language more consistent while avoiding duplicate syntaxes for things.
I do think this is cleaner than the earlier proposals. So I think people should look either of the last two examples and ignore naming.
I do get that there can be fatigue around seeing many small variations and similar proposals, but I would advise people to give this a serious consideration.
/poll What is your general thought/opinion on removing if then else in order to make the language more consistent?
Sounds Great
Minor Gain
Indifferent
Minor Loss
Bad Idea
Please add any thoughts or comments below.
I think the main discussion from people on this thread should pause for a short bit to let other's opinions roll in.
I hope folks check out the summary and list of "advantages" which I've been updating.
The wording of the survey question "to make the language more consistent" doesn't fully capture the 10 advantages I've listed.
We should be clear that the vote covers the introduction of one line pattern matching. If then else could be removed without introducing one-line pattern matching. Presumably since it says "see suggested change above" it also includes the introduction of one line pattern matching.
Yeah, I was assuming it would include that, but I think that specific could be changed later. I think the bigger question of the general change to if then else is what is most important here.
I think I should maybe try a different approach to convey my feelings about this.
I think if you imagine the perfect syntax for conditionals in Roc, like the Platonic ideal, there is no possible room for improvement, no one could possibly argue otherwise...the benefit to the language to switching to that syntax would be microscopic
my main preoccupation with this topic is that it feels unhealthy that we're spending this much time and energy discussing something in this category
I definitely think syntax is important, but there seems to be a persistent mismatch here between how big of a delta I think is even possibly achievable here and how big others think it is
there are clearly advantages to this proposal (although I'm pretty surprised nobody has brought up the downside of greater indentation, since that's come up in a lot of past syntax discussions)
but also clearly downsides, such as either when meaning two different things or else needing to introduce a new keyword (at which point you have when, which is necessary for pattern matching, and either cond or if)
among others
but at the end of the day, I just don't think this question is the right thing to spend so much energy on
for example, I'm fine with revisiting the design of Bool for reasons such as beginners finding it confusing, or some of the original assumptions behind that experiment turning out to be invalid, etc. - but it definitely seems like the main reason we have another entire thread revisiting Bool's design is because changing it might facilitate this syntax proposal
and I don't think that's a good reason to reconsider Bool's design
@Richard Feldman @Ayaz Hafiz @Ayaz Hafiz @Anton @Brendan Hansknecht @Bryce Miller @Georges Boris @David Mell @XeroOl @Brian Carroll @Luke Boswell
Thanks for sharing your opinion everyone!
Clearly there is not tremendous support for the proposal.
It was kind of trivial. Sorry to have taken up so much space on this.
Matthias Toepp has marked this topic as resolved.
Last updated: Jun 16 2026 at 16:19 UTC