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
Kotlin:
// "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)
Matthias Toepp said:
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
Transformed to roc could be either:
message = if (num % 2 == 0) "even" else "odd"
or
message = if num % 2 == 0 then "even" else "odd"
Matthias Toepp said:
Kotlin:
// "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)
transformed to roc could be:
size =
when x is
Small ->
"small"
Medium ->
"medium"
else
"large"
size =
when
y < 10 ->
"small"
y < 100 ->
"medium"
else
"large"
(Kotlin examples were taken from https://learnxinyminutes.com/docs/kotlin/ )
THE IDEA: have a cond like when structure which is highly consistent with the when..is and retain if for quick single line use (with or without the thenkeyword), similar to how Kotlin does this.
I'd prefer to add an -> to the else for consistency, similar to kotlin.
Kotlin allows the multiline if else as well. We could do that too for people who prefer less indentation.
My preference would be
size =
if
x < 10 ->
"small"
x < 100 ->
"medium"
_ ->
"large"
While still alowing the current multiline if-else as well
@Anton I would be fine with that or even calling it cond.
The main point for me is that even kotlin has this, and they even use when which we already have.
(I think when looks a little more robust than if, and else looks more robust than _->. It's not a big deal either way).
Having conditions surrounded by three keywords else if then and pushing the conditions out of alignment is an anti-pattern as far as I'm concerned.
It feels like:
public class JavaBoilerplate {
public static void main(String[] args) {
...it's unnecessary boilerplate
....and we already have a first class, boilerplate-free, multi-line decision structure format: when is!!!
There is a reason why Kotlin has this syntax and why Python (and F# and others) have elif and why Haskell has multiway if, and why lisp has cond. I think it's the same reason we spend our time and money to cover drywall screws and seams. else if then are implementation details like drywall screws. We want to focus on the conditions as if they were pictures hanging on a wall.
What we have now is already unusual syntax in that we use then.
I do like the then when used on a single line like here. Because it looks very consistent with the 4-letter else.
With the formatter I would correct non-deeply nested cases of if-else to the cond way and leave the rest as is.
Anton said:
I do like the
thenwhen used on a single line like here. Because it looks very consistent with the 4-letter else.With the formatter I would correct non-deeply nested cases of if-else to the cond way and leave the rest as is.
me too
:+1: Time for others to weigh in I suppose
If we do something like this, I do think we should keep _ ->. It will also feel more natural due to being used in other parts of matching Ok _ for example.
This definitely is growing on me:
if
x < 10 ->
"small"
x < 100 ->
"medium"
_ ->
"large"
That said, I don't think it is a good a idea to have two syntaxes for if then else.
And if we have to pick this or the current syntax, I would pick the current syntax because it can be used inline and will be more familiar to beginners.
I wouldn't mind having this alternate syntax based on when while keeping the usual if then else for one-liners and easier onboarding
Expanding when sounds like a much better way to add this to me.
when already has this feature, it just looks terrible.
when 0 is
_ if x < 0 -> "small"
_ if x < 100 -> "medium"
_ -> "large"
so:
when
x < 10 ->
"small"
x < 100 ->
"medium"
_ ->
"large"
when x is
1 ->
"small"
10 ->
"medium"
_ ->
"unknown"
if x < 10 then
"small"
else if x < 100 then
"medium"
else
"large"
if x > y then "BT" else "LT"
all valid roc code. this would be my pitch.
Yeah, that is the best I can think of. Was trying to think of a more general merging, but I think it is best to just split when into two distinct forms like above. The only clean way to keep both merged (that I can think of) is to enable more complex structures. Where you do something like:
when Bool.true is
x < 10 ->
"small"
x < 100 ->
"medium"
_ ->
"large"
# Then this would also allow for other constants instead of just Bool.true. like:
# Pretend we have tag [Success, Failure]
when Success is
tryThing1 -> ...
tryThing2 -> ...
_ -> # This is the everything failed case.
# No idea if/how this would work with Result for example.
# could you do:
when Ok _ is
...
But yeah, I think the above is likely too flexible/open. Not sure what type of larger ramification it might have.
As such, I think splitting when will lead to a very limited but know clean use of the language feature.
I think the above is likely too flexible/open.
I think so as well
we could encourage people to use the cond-like structure for multi-line and if for short, one line use.
I personally don't like the idea of having 2 parallel syntaxes for if. However, if we are to go this route, encouraging people isn't a strong enough guarantee. roc format should have some metric for rewriting between them.
David Mell said:
I personally don't like the idea of having 2 parallel syntaxes for
if. However, if we are to go this route, encouraging people isn't a strong enough guarantee.roc formatshould have some metric for rewriting between them.
I don't like having two syntaxes either, and we don't really need two ... it's just that if then else works good for one line use and the when style works good for multi-line!
Technically we could scrap if, then and else for single line use and eliminate three keywords and settle for one nice multi-line when [is] structure, like Kotlin uses when (shown in the first posts).
… i.e. we could get by without the if then and else keywords and only be left with this for decision structures:
(Kotlin when as roc:)
size =
when x is
Small ->
"small"
Medium ->
"medium"
_ ->
"large"
size =
when
y < 10 ->
"small"
y < 100 ->
"medium"
_ ->
"large"
(see the first posts for the Kotlin version).
That seems like a good starting point for discussion/consideration, considering how simple that is. Then the question is how much syntax do we want to add?...Do we want when to be if?...Do we want -> to be then and do we want _-> to be else? Do we need if then else syntax for single line use? Is there a way to change that syntax (of both decision structures) so it can work for single line use...?
..but the enhanced simplicity, consistency and readability (alignment of conditions and less keyword boilerplate/noise) of the above is quite powerful I think....and it's used in Kotlin!
then we are back to the same suggestions we already discussed in other threads
@Georges Boris
After pushing on this idea, and having gotten all the feedback that we've gotten, it has led me to a quite different perspective and I'm hoping that others will share this perspective/approach moving forward....
Developing what I was saying in the comments immediately before yours...
In the past it seemed like the conversation revolved around the syntax we already have, i.e. saying we already have syntactic sugar with the if, then and else keywords, we don't want to add keywords and syntactic sugar and on syntactic sugar (with the proposed elif, el,oref), we appreciate having one line if, our strangeness budget is maxed out so lets not spend more on a cond-like structure, and the when/cond-like structure takes up more space, and a cond-like structure is redundant with if, then and else`.
Instead, now the situation looks (to me) like:
We may not actually be proposing a bizarro-world, strangeness-budget exploding syntax if we are exploring a syntax like Kotlin's.
I now also appreciate that our current syntax is already quite unconventional in using then. Ruby being the most popular language that has then, and Ruby has only about 1 or 0.66% of programming language popularity.
That means that if then else is spending the strangeness budget and the complexity budget and the keyword budget and an inconsistency budget and creating misalignment of conditions and syntactic noise/boilerplate.
I am now able to succinctly characterize a core challenge on this issue as: if then else is great for one line use and when style is great for multiline. I don't think there is an technical reason why that cannot be resolved, if the desire is there.
I now see that what we are proposing with a cond-like structure as actually simpler, more consistent (with when), it could exist without theif, else and thenkeywords, and also fix the alignment issue of else if and eliminate the syntactic noise/boilerplate of the if then else keywords.
In terms of using extra space...If the cond-like syntax follows the layout of when .is (as proposed) and indentation can already be at any number of spaces (and no one even wants to talk about reducing the default number of spaces because they think its a problem with when is), then it's hard to see how the proposed when is like layout of a cond-like structure is unacceptable because it adds more space.
For those reasons, (if we can agree on them), I'm thinking the syntax shown immediately above could be considered the better essential starting point. So I'm now suggesting that that syntax should be what roc has if we can't agree on anything else. Then if we want more syntax we can see if or how we want to add to that or change it.
For the sake of correctness, bash also has a then and bash is reasonably popular
So, to keep track, this is the final proposal?
While allowing single line if-then-else but a compiler error on multiline?
EDIT: I re-read your message: your suggestion appears to be to completely remove if
I believe that a proposal where we keep if-then-else would have a significantly higher chance of passing.
Just a comment on popularity/familiarity. I don't think kotlin having similar structures means much. Kotlin is new and is gaining popularity, but still has not been used by that many people. It could be argued that ruby has probably been used by more people over its many years of life and thus is a more familiar syntax to a larger audience. In general, I am trying to say that we shouldn't anchor to other specific languages much.
I think familiarity or copying here is pretty minor. The reason being that when is already part of our weirdness budget. So we have a decent amount of room to play with it. Yes, similar structures exist in other languages, but they are less common and only recently becoming more popular.
if on the other hand, has a few common forms, and a lot more expectations of what it should look like. if then else is a tiny bit weird, but not in the same way as when. I think that removing if or changing it to the syntax below would cost much more in weirdness than any of the proposed changes to when
if
x < 20 -> Small
x > 100 -> Large
_ -> Medium
Anton said:
For the sake of correctness, bash also has a
thenand bash is reasonably popular
On https://www.tiobe.com/tiobe-index/ Bash has a popularity rating of 0.21%, it's listed as the 49th most popular language below prolog and forth. Those metrics may not be accurate somehow but that's all I have to go by. Clearly the shell is quite popular but people may not script with it very much compared to their use of other languages. There are a lot of programmers who use windows and not linux.
To be clear, I'm not necessarily opposed to using then. I'm trying to shift the conversation, based on what I wrote above, to suggest that if we flat out need to reject an option between either a cond-like decision structure or if then else, then based on the values we've expressed (as I understand them), it seems we should decide against if then else and go with the cond-like structure. But again that doesn't mean we must reject then.
Brendan Hansknecht said:
Just a comment on popularity/familiarity. I don't think kotlin having similar structures means much. Kotlin is new and is gaining popularity, but still has not been used by that many people. It could be argued that ruby has probably been used by more people over its many years of life and thus is a more familiar syntax to a larger audience. In general, I am trying to say that we shouldn't anchor to other specific languages much.
In past discussions, it seemed that a cond-like structure has been rejected with the rationale that it eats into the strangeness budget and adds keywords and causes redundancy with if then along with the other reasons I listed above.
Kotlin happens to use when like roc does. In addition it uses when in a way that means that if then and else could be eliminated (if desired). This is more then a solution to those objections raised against a cond-like structure in the past. It actually turns the arguments on their heads. If we used when the way Kotlin also uses it for a cond-like structure, not only could we avoid adding keywords but we could reduce keywords ( if, then and else) and we could avoid adding redundant syntax, and extra keywords, and have more consistent decision structures and have proper alignment of conditions and have less syntax noise and boiler plate.
On https://www.tiobe.com/tiobe-index/ Bash has a popularity rating of 0.21%, it's listed as the 49th most popular language below prolog and forth. Those metrics may not be accurate somehow but that's all I have to go by. Clearly the shell is quite popular but people may not script with it very much compared to their use of other languages. There are a lot of programmers who use windows and not linux.
A useful contradictory datapoint seems to be this section of the stack overflow developer survey of 2022. Where bash is ranked 7th with 29% users saying that they've used it for extensive development work over the past year.
I suggest we make a zulip poll on your proposal @Matthias Toepp with pros and cons summarized above it. I can do it today or tomorrow, or if you'd like to do it that's fine by me as well.
Sure. i'll give it a try.
I'll post it here first for review/addition of pros and cons.
please included the proposal which I listed above which includes the redundant if and also zero-args when
it seems like we could ask a lot of questions.
For me somehow there has been a lot of progress in how I think about this (as I described above) but there is still the unresolved issue of if then else working nice for single lines and cond-like working nice for multi-line. It seems like that should be solvable, but I don't know how to solve it yet.
when x < 100 -> "less" _-> "greater" # looks bad for one line, great for multiline.
... (intermediate possibilites with mixed results)
...
if x < 100 then "less" else "greater" # looks great for one line, bad for multiline.
-> could be replaced with then and _-> could be replaced with else even for when is...
I imagine there is an acceptable way to have a nice single line and multline but I don't know what it is (yet).
So I feel like we don't have a home run until we can offer a nice one line solution.
Yeah, that's a pain point indeed
I'll give that some more thought when my mind is fresher.
Matthias Toepp said:
So I feel like we don't have a home run until we can offer a nice one line solution.
I know there's a lot of activity on this discussion, but I again want to share a disconnect I'm feeling - I don't think the current proposal is significantly closer to being a change I'd accept to the language. I hate to be a downer about it, but at the same time when I see a disconnect like this, I want to be open about what I'm thinking! :sweat_smile:
some specific points of disconnect I'm feeling:
then to be zero percent weird; the only upside I see to removing it from the language would be freeing up a reserved keyword. Actually, the first time I've ever heard then called weird is in this thread!when and if ones) wouldn't justify a language change. I can see the upsides, it's just that I think the downsides still outweigh them by a wide margin.like I said earlier, I really am genuinely open to accepting a proposal if it seems like a good fit, but at the same time I want to be honest that the evaluation metric I have to use here is "does this seem like a worthwhile and positive change for the language overall?" and the most recent proposals don't feel significantly closer to meeting that bar than the originals did.
@Georges Boris and @Anton I'll leave it to others if they/you want to spend any more effort on this (with a survey etc).
Georges Boris said:
so:
when x < 10 -> "small" x < 100 -> "medium" _ -> "large" when x is 1 -> "small" 10 -> "medium" _ -> "unknown" if x < 10 then "small" else if x < 100 then "medium" else "large" if x > y then "BT" else "LT"all valid roc code. this would be my pitch.
@Richard Feldman just to make sure - for the pitch above, would you consider the downside to be the redundancy of if/else and the when without an arg? or something else?
I'm fine in not changing anything but I do consider the when with 0-arg to be quite elegant in comparison to the if/else chain - it has upsides when thinking about readability and code versioning diffs and there is no downsides to newcomers and one-liners if we keep if/else as an additional possibility as well.
I won't be pushing this for longer but I don't see the "downsides that vastly outweigh the upsides" in this scenario to be honest.
@Richard Feldman I don't really wish to push on the point further, but just for posterity I'll point out that you didn't address that the existing approach surrounds conditions by 3 keywords else if x then which could be eliminated altogether.
as i said above:
Having conditions surrounded by three noisy/boilerplate keywords else if then and pushing the conditions out of alignment is an anti-pattern as far as I'm concerned.
It feels like:
public class JavaBoilerplate {
public static void main(String[] args) {
...it's unnecessary boilerplate
....and we already have a first class, boilerplate-free, multi-line decision structure format: when is!!!
There is a reason why Kotlin has this syntax and why Python (and F# and others) have elif and why Haskell has multiway if, and why lisp has cond. I think it's the same reason we spend our time and money to cover drywall screws and seams. else if then are implementation details like drywall screws. We want to focus on the conditions as if they were pictures hanging on a wall.
Anyway, I do appreciate that you're trying to gently spare us from greater disappointment after investing more in this! :smile:
Georges Boris said:
Richard Feldman just to make sure - for the pitch above, would you consider the downside to be the redundancy of if/else and the when without an arg? or something else?
I'm fine in not changing anything but I do consider the when with 0-arg to be quite elegant in comparison to the if/else chain - it has upsides when thinking about readability and code versioning diffs and there is no downsides to newcomers and one-liners if we keep if/else as an additional possibility as well.
so at a baseline, whenever I'm evaluating a potential change to the language, "introduces additional syntax" goes into the category of "downsides" - and that includes making existing syntax situationally work differently (e.g. when working differently depending on whether there's also an is). So I wouldn't say "there is no downside to newcomers" because anything that makes the grammar of the language larger is a downside, and actually I think that downside affects beginners most of all. :big_smile:
but of course the grammar has expanded over time, and will in the future. In each case, the question has to be whether the upside is worth that downside. If the bar is set at "this is slightly better, let's add it!" then very quickly the language would become absolutely enormous, because there are lots of ways to add syntax which under certain specific circumstances reads more nicely.
it will be interesting to see where gleam goes with this (they haven't introduced if else)
https://gleam.run/book/tour/case-expressions.html
// Pattern matching on a Bool value is the Gleam alternative
// to the if else statement found in other languages.
case some_bool {
True -> "It's true!"
False -> "It's not true."
}
so the line has to be drawn somewhere, and unfortunately it's innately subjective where it should be drawn.
some relevant examples in both directions:
if from Elm back around its 0.13 release, I was among those in favor of removing it to simplify the grammar.T x y = ... proved enough of an ergonomics downgrade compared to (x, y) = ... that I reconsidered and we ended up adding tuples to Roc after all.| separators to pattern matches in when in Roc. (Elm does not have these.) I that case, I think the upside outweighs the downside because I know from experience that otherwise it's common to have to restructure branches to extract helper functions to ensure that a group of branches is doing the same thing. This makes the code a lot harder to follow because you have to jump around to see what it's doing, as opposed to having it right there next to the branchanyway, hope that helps - and thanks for understanding on all this! :heart:
@Richard Feldman
The latest proposal: https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/1.20line.20pattern.20match.20.2B.20.60when.20is.60-like.20bool.20structure
Not only does that proposal not add syntax or redundant decision structures or syntax sugar to roc, but it removes syntax. It simplifies roc, makes it more powerful, more consistent, more readable, with enhanced diff and refactorability...there's a whole list of details on the advantages listed in the first posts there.
what do others think?
I'm really confused about these different if/when threads that are kinda about the same thing? :sweat_smile:
Last updated: Jun 16 2026 at 16:19 UTC