Stream: ideas

Topic: kotlin-like decision structures


view this post on Zulip Matthias Toepp (May 08 2023 at 10:53):

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

view this post on Zulip Matthias Toepp (May 08 2023 at 10:54):

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)

view this post on Zulip Matthias Toepp (May 08 2023 at 11:02):

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"

view this post on Zulip Matthias Toepp (May 08 2023 at 11:10):

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"

view this post on Zulip Matthias Toepp (May 08 2023 at 11:24):

(Kotlin examples were taken from https://learnxinyminutes.com/docs/kotlin/ )

view this post on Zulip Matthias Toepp (May 08 2023 at 11:27):

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.

view this post on Zulip Anton (May 08 2023 at 12:03):

I'd prefer to add an -> to the else for consistency, similar to kotlin.

view this post on Zulip Anton (May 08 2023 at 12:05):

Kotlin allows the multiline if else as well. We could do that too for people who prefer less indentation.

view this post on Zulip Anton (May 08 2023 at 12:08):

My preference would be

size =
    if
        x < 10 ->
            "small"
        x < 100 ->
            "medium"
        _ ->
            "large"

view this post on Zulip Anton (May 08 2023 at 12:10):

While still alowing the current multiline if-else as well

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

@Anton I would be fine with that or even calling it cond.

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

The main point for me is that even kotlin has this, and they even use when which we already have.

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

(I think when looks a little more robust than if, and else looks more robust than _->. It's not a big deal either way).

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

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.

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

What we have now is already unusual syntax in that we use then.

view this post on Zulip Anton (May 08 2023 at 13:12):

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.

view this post on Zulip Matthias Toepp (May 08 2023 at 13:25):

Anton said:

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.

me too

view this post on Zulip Anton (May 08 2023 at 13:28):

:+1: Time for others to weigh in I suppose

view this post on Zulip Brendan Hansknecht (May 08 2023 at 14:34):

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.

view this post on Zulip Brendan Hansknecht (May 08 2023 at 14:38):

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.

view this post on Zulip Georges Boris (May 08 2023 at 14:40):

I wouldn't mind having this alternate syntax based on when while keeping the usual if then else for one-liners and easier onboarding

view this post on Zulip Brendan Hansknecht (May 08 2023 at 14:40):

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"

view this post on Zulip Georges Boris (May 08 2023 at 14:43):

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.

view this post on Zulip Brendan Hansknecht (May 08 2023 at 14:50):

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.

view this post on Zulip Anton (May 08 2023 at 14:52):

I think the above is likely too flexible/open.

I think so as well

view this post on Zulip Matthias Toepp (May 08 2023 at 18:18):

we could encourage people to use the cond-like structure for multi-line and if for short, one line use.

view this post on Zulip David Mell (May 08 2023 at 22:42):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 03:08):

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 format should 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!

view this post on Zulip Matthias Toepp (May 09 2023 at 03:08):

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).

view this post on Zulip Matthias Toepp (May 09 2023 at 04:42):

… 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"

view this post on Zulip Matthias Toepp (May 09 2023 at 04:51):

(see the first posts for the Kotlin version).

view this post on Zulip Matthias Toepp (May 09 2023 at 05:30):

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!

view this post on Zulip Georges Boris (May 09 2023 at 08:28):

then we are back to the same suggestions we already discussed in other threads

view this post on Zulip Matthias Toepp (May 09 2023 at 13:49):

@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....

view this post on Zulip Matthias Toepp (May 09 2023 at 13:49):

Developing what I was saying in the comments immediately before yours...

view this post on Zulip Matthias Toepp (May 09 2023 at 13:50):

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`.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:50):

Instead, now the situation looks (to me) like:

view this post on Zulip Matthias Toepp (May 09 2023 at 13:50):

We may not actually be proposing a bizarro-world, strangeness-budget exploding syntax if we are exploring a syntax like Kotlin's.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:50):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:51):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:51):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:51):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:51):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 13:51):

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.

view this post on Zulip Anton (May 09 2023 at 14:09):

For the sake of correctness, bash also has a then and bash is reasonably popular

view this post on Zulip Anton (May 09 2023 at 14:13):

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

view this post on Zulip Anton (May 09 2023 at 14:39):

I believe that a proposal where we keep if-then-else would have a significantly higher chance of passing.

view this post on Zulip Brendan Hansknecht (May 09 2023 at 14:44):

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

view this post on Zulip Matthias Toepp (May 09 2023 at 16:04):

Anton said:

For the sake of correctness, bash also has a then and 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.

view this post on Zulip Matthias Toepp (May 09 2023 at 16:08):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 16:49):

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.

view this post on Zulip Anton (May 09 2023 at 16:49):

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.

view this post on Zulip Anton (May 09 2023 at 16:59):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 17:02):

Sure. i'll give it a try.

view this post on Zulip Matthias Toepp (May 09 2023 at 17:03):

I'll post it here first for review/addition of pros and cons.

view this post on Zulip Georges Boris (May 09 2023 at 17:13):

please included the proposal which I listed above which includes the redundant if and also zero-args when

view this post on Zulip Matthias Toepp (May 09 2023 at 17:51):

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.

view this post on Zulip Anton (May 09 2023 at 17:56):

Yeah, that's a pain point indeed

view this post on Zulip Matthias Toepp (May 09 2023 at 18:00):

I'll give that some more thought when my mind is fresher.

view this post on Zulip Richard Feldman (May 09 2023 at 18:44):

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:

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 21:22):

@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).

view this post on Zulip Georges Boris (May 09 2023 at 21:38):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 21:38):

@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.

view this post on Zulip Matthias Toepp (May 09 2023 at 22:10):

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.

view this post on Zulip Matthias Toepp (May 09 2023 at 22:13):

Anyway, I do appreciate that you're trying to gently spare us from greater disappointment after investing more in this! :smile:

view this post on Zulip Richard Feldman (May 09 2023 at 23:07):

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.

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

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."
}

view this post on Zulip Richard Feldman (May 09 2023 at 23:12):

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:

view this post on Zulip Richard Feldman (May 09 2023 at 23:13):

anyway, hope that helps - and thanks for understanding on all this! :heart:

view this post on Zulip Matthias Toepp (May 11 2023 at 18:54):

@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.

view this post on Zulip Richard Feldman (May 11 2023 at 23:19):

what do others think?

view this post on Zulip Georges Boris (May 12 2023 at 01:46):

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