Stream: ideas

Topic: Abilities syntax


view this post on Zulip Zeljko Nesic (Mar 17 2022 at 12:00):

Originally posted in Github: https://github.com/rtfeldman/roc/pull/2721#issuecomment-1069279849

I have a bad feeling about this syntax.

declaration : field, field -> Type field | field supports Ability

Looking from far away it reads a bit weird ...

Maybe it's the fact that | is so thin, or that I instantly read it as: "this pipes to that" but skimming trough definitions with abilities, my eyes hurt.
Maybe it's because in Haskell typeclasses are written in front, and in Elm we usually do
stuff : Config data msg -> data -> Things data msg
Meaning, we we treat a type variable inside this function is specified at the start of the function declaration.

My proposal:
declaration : field supports Ability @ field, field -> Type field

and sortBy would read like this

sortBy : field supports Ordering @ List elem, (elem -> field) -> List elem

As a final suggestion I would remove supports and replace it with a symbol too. Why? Its a letter construct that is not essential for the reading of that line.

Now, Editor is the reason why I am writing this. Roc's syntax so far was really unambiguous and straight forward in a sense that the decision tree for the user was really simple. With each key we could know that you have done with that and moved to another thing (from writing a function name to listing arguments, from listing arguments to specifying return type or adding another argument etc.).

With the ability declaration at the end I am not sure how to lend it as a easy affordance that you are done specifying return type, or that you'd like to add or modify one of the ability specifications. I am not saying it is impossible, and that language must bend to the needs of the Editor.

I am just stating my concern that A E S T H E T I C S are off with current design of the abilities syntax. :)

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 12:01):

Please feel free to chime in with the ideas on the syntax!

view this post on Zulip Folkert de Vries (Mar 17 2022 at 12:53):

None of these look great

sortBy : List elem, (elem -> field) -> List elem | field supports Ordering

sortBy : Ordering field => List elem, (elem -> field) -> List elem

sortBy : field has Ordering => List elem, (elem -> field) -> List elem

Though I generally prefer to have the constraint first, and then the type. compare haskell's constraint syntax

sortBy : Ord field => List elem, (elem -> field) -> List elem

also how do we format any of these on multiple lines?

view this post on Zulip Folkert de Vries (Mar 17 2022 at 12:54):

also, how do we deal with multiple abilities on the same type variable, or multiple variables, each with separate abilities

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:03):

| foo supports Bar, Baz, blah supports X, Y

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:03):

that's the current proposed syntax, at any rate

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:04):

it works because type variable names are always lowercase and ability names are always uppercase

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:06):

I'm personally not a fan of the "constraint comes first" syntax because - compare these two:

Dict.update : Dict k v, k, (v -> v) -> Dict k v | k supports Hashing, Equating
Dict.update : k supports Hashing, Equating => Dict k v, k, (v -> v) -> Dict k v

it's a dictionary; I know the key needs to support hashing and equating!

I'm reading the docs for Dict.update because I want to know the shape of the function I'm going to be calling

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:07):

because I use dictionaries all the time but not Dict.update very often

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:07):

so with the constraint up front, I have to read past the least useful information every time before getting to the part of the type definition that actually has information I didn't know already

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:09):

technically to fully understand the type, both pieces of information need to be in there somewhere, but the constraints are rarely what I came to the function to look up

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:10):

so I prefer having them at the end, so I can learn what I need to learn first and then stop reading

view this post on Zulip Richard Feldman (Mar 17 2022 at 13:10):

in the common case where I already know what the constraint is going to be based on the operation

view this post on Zulip Brian Carroll (Mar 17 2022 at 15:04):

Maybe we could take some inspiration from Rust's multiline where syntax?

pub fn insert_all<K, V, I>(map: &mut SendMap<K, V>, elems: I)
where
    K: Clone + Eq + Hash,
    V: Clone,
    I: Iterator<Item = (K, V)>,
{
    for (k, v) in elems {
        map.insert(k, v);
    }
}

view this post on Zulip Brian Carroll (Mar 17 2022 at 15:04):

Although we don't have the curly braces, just indentation

view this post on Zulip Brian Carroll (Mar 17 2022 at 15:05):

update : Dict k v, k, (v -> v) -> Dict k v
   where k supports Hashing, Equating
update = \dict, key, func ->
     # function body

view this post on Zulip Tommy Graves (Mar 17 2022 at 15:34):

Personally I like the multiline syntax with where + supports, because it makes the type signature itself easy to read (to Richard's point, that's probably what you care about more than the abilities supported most of the time) and it doesn't look like syntactical gobbledygook to someone who is first seeing the language.

view this post on Zulip Richard Feldman (Mar 17 2022 at 16:20):

Editor is the reason why I am writing this. Roc's syntax so far was really unambiguous and straight forward in a sense that the decision tree for the user was really simple. With each key we could know that you have done with that and moved to another thing (from writing a function name to listing arguments, from listing arguments to specifying return type or adding another argument etc.).

With the ability declaration at the end I am not sure how to lend it as a easy affordance that you are done specifying return type, or that you'd like to add or modify one of the ability specifications.

this is a fair point, although once you've finished autocompleting the return value, we could make the w key show an autocomplete for adding a where clause

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 16:33):

update : Dict k v, k, (v -> v) -> Dict k v
update : k supports Hashing, Equating
update = \dict fn ->
  _

Just writing it out it seems that even where is not needed if we allow it to be written (indented) in the next line?

update : Dict k v, k, (v -> v) -> Dict k v
  k supports Hashing, Equating
update = \dict fn ->
  _

view : Config state render, state -> UI state renderer
  state supports Rendering, Memoising
  renderer supports LowLevelGraphics
view = \cfg s ->
  _

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 16:35):

Yes, I think that new line looks great! :)

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 16:44):

I like the new line with or without where. I think the new line in general is really important for readability

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 16:46):

better still we keep out the supports at all.

update : Dict k v, k, (v -> v) -> Dict k v
  k | Hashing, Equating
update = \dict fn ->
  _

view : Config state render, state -> UI state renderer
  state | Memoising, Encoding
  renderer | LowLevelGraphics
view = \cfg s ->
  _

I totally agree that we should read this as that as X supports Y, but I'd remove a whole word from definitions.

I see that is _harder_ to explain, but one of the Roc's beauties is that you are not writing English prose that we have to interpret, as in "type alias XY, data Y" but straight any letter is a Symbol (except header thingy).

Finding good symbol for being association for supports and easy one to reach on the keyboard would help reading and writing Roc.

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 17:23):

Is it true that whenever you have a type variable that you need to specify what that type variable does, unless you are passing it back as a result.

foo : Some a -> Str
foo ... .

Basically result of foo doesn't depend on a so we can safely way that a = *

foo : Some * -> Str
foo = \s -> _

If we return a then also we might not care what it does, as in

baz : Some a -> Result Errors a
baz = \s -> _

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 17:27):

But if foo uses a it has to state which ability it uses.

foo : Some a -> Str
  a | StrEquating
foo = \ s -> Str.append "foo" (equate a)

view this post on Zulip Ayaz Hafiz (Mar 17 2022 at 17:28):

Yes - * is a synonym for a type variable that only appears once, and hence is unbound

view this post on Zulip Zeljko Nesic (Mar 17 2022 at 17:30):

yes I am trying to see what are the cases when you actually write out abilities.

view this post on Zulip Derek Gustafson (Mar 17 2022 at 17:30):

I think needing to state an ability is kind of a logistical requirement. How much can you do with an unknown type?

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 17:45):

Quick comment on syntax:
I like the new line with or without where. I think the new line in general is really important for readability.

view this post on Zulip Richard Feldman (Mar 17 2022 at 17:58):

what would a multiline type annotation look like without a when equivalent?

e.g.

update :
    Dict k v,
    k,
    (v -> v)
    -> Dict k v
    where
        k supports Hashing, Equating
update = ...

how would that look if it didn't have a separator like when?

or what if the return type itself was so long it needed to be multiline, e.g. instead of -> Dict k v it was something like

->
    Dict
    k
    v

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:05):

update :
    Dict k v,
    k,
    (v -> v)
    -> Dict k v

Is surprisingly painful to read by itself. I think the where doesn't help or hurt it.

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:07):

Oh, I think I know the issue. is this nicer?

update :
        Dict k v,
        k,
        (v -> v)
    -> Dict k v

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:08):

Hmmm....maybe not quite right either.....

Anyway. I guess I am just pointing out that I dont think the where really changes the readability of theses examples. I think the default syntax is just rough to read.

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:12):

I wouldn't actually use it in a case like this - it comes up more if the types are really long and if it's all on one line the line is huge

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:12):

but the bigger question is more about what would it look like without where?

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:39):

Just put the spec where you would put the where.

update :
        Dict k v,
        k,
        (v -> v)
    ->
        Dict
        k
        v
    k supports Hashing, Equating

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:39):

This is pretending the return type had a super long name

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:40):

With shorter names:

update :
        Dict k v,
        k,
        (v -> v)
    -> Dict k v
    k supports Hashing, Equating

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:40):

Not sure why the where matters

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 18:41):

Just the tabbing should matter

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:56):

:thinking: here's an idea - what if instead of where it was a comma?

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:57):

update : Dict k v, k, (v -> v) -> Dict k v,
    k supports Hashing, Equating
update :
        Dict k v,
        k,
        (v -> v)
    -> Dict k v,
    k supports Hashing, Equating

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:57):

so then there's no need for an indentation rule

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:58):

and comma pretty universally indicates "there's more here, we're not done yet" so it's pretty clear to me that what comes after the comma is more information that goes with the type annotation

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:59):

also works on a single line, so you can write it that way even if the formatter will change it to multi-line by convention:

update : Dict k v, k, (v -> v) -> Dict k v, k supports Hashing, Equating

view this post on Zulip Richard Feldman (Mar 17 2022 at 18:59):

(I agree with the idea that we should have multiline be the formatting convention!)

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 20:54):

That looks off due to the comma between Hashing and Equating.

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 20:54):

Makes it look like Equating is just it's own thing.

view this post on Zulip Richard Feldman (Mar 17 2022 at 20:55):

could do like k supports Hashing & Equating or k supports Hashing + Equating

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 20:57):

That works. Though I'm sure it will cause some new users to think of tuples.

view this post on Zulip Brendan Hansknecht (Mar 17 2022 at 20:57):

Just the fact that there is a comma in general. Not a big deal, just a note

view this post on Zulip Richard Feldman (Mar 17 2022 at 21:05):

all the ML family languages that have tuples use parens around them, so should be ok I think!

view this post on Zulip Pit Capitain (Mar 18 2022 at 06:17):

Richard Feldman said:

also works on a single line, so you can write it that way even if the formatter will change it to multi-line by convention:

update : Dict k v, k, (v -> v) -> Dict k v, k supports Hashing, Equating

This could be read as: update is getting three parameters and returning two values :thinking:

view this post on Zulip Anton (Mar 18 2022 at 08:43):

How about update : Dict k v, k, (v -> v) -> Dict k v & k supports Hashing, Equating ?

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 10:30):

Very hard to distinguish what where is it k & v

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 10:34):

The root of the problem is that we are tying to write two orthogonal type definitions.
When we join them we end-up with a sausage long definition. Our eyes are maybe not trained to look for anything beyond return type.

view this post on Zulip Anton (Mar 18 2022 at 10:42):

I agree, convention should be to put it on its own line, how about this:

update : Dict k v, k, (v -> v) -> Dict k v
    & k supports Hashing, Equating

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 10:44):

Me gusta newline mucho!

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 10:44):

but that '&' maybe can be '@'
as in ~a~bility

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 10:45):

update : Dict k v, k, (v -> v) -> Dict k v
    @ k supports Hashing, Equating

view this post on Zulip Anton (Mar 18 2022 at 10:57):

That looks good, one small disadvantage is that @ is a bit harder to type on azerty keyboards

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 11:17):

fair point!

how about

update : Dict k v, k, (v -> v) -> Dict k v
    : k supports Hashing, Equating

view this post on Zulip Anton (Mar 18 2022 at 11:53):

I'm leaning towards using a different symbol to convey a different meaning but it's a good contender.

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 13:51):

update : Dict k v, k, (v -> v) -> Dict k v
    | k supports Hashing, Equating
update : Dict k v,
        k,
        (v -> v) ->
        Dict k v
    | k supports Hashing, Equating
# Curses on thou who formats code like this! Let the editor do its bidding, ye!

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 13:51):

Maybe all along it was just enforcing the newline rule?

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 13:52):

update : Dict k v, k, (v -> v) -> Dict k v
    | k supports Hashing, Equating
    | v support Modulating
update = \dict key value  ->

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 13:54):

This breaks another thing, and that is direct connection of the parameter and its declaration.

They are little too separated like this ...

view this post on Zulip Anton (Mar 18 2022 at 15:07):

I'm not sure it is possible to improve on that aspect without making bigger sacrifices.

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 15:21):

Yes, something gotta give :)

view this post on Zulip Brendan Hansknecht (Mar 18 2022 at 15:27):

I like this form quite a bit. Find it very readable.

update : Dict k v, k, (v -> v) -> Dict k v
    | k supports Hashing, Equating
    | v support Modulating
update = \dict key value  ->

view this post on Zulip Zeljko Nesic (Mar 18 2022 at 16:07):

Almost like abilities are like a back of the envelope of the products.
Where you check facts of the thing, almost as a necessary supplement.

view this post on Zulip Kevin Gillette (Mar 19 2022 at 05:24):

Agreed, the compact multiline form Brendan Hansknecht quoted is pretty readable.

Presumably there shouldn't be a pluralization difference in the example (supports not support)?

view this post on Zulip Kevin Gillette (Mar 19 2022 at 05:27):

When using types which require abilities (as Dict may require Hashing and Equating), do those need to be spelled out if the function is not using them directly? Can Roc accurately infer required abilities even if they're not declared?

view this post on Zulip Kevin Gillette (Mar 19 2022 at 05:32):

Could we also do something like the following?

update : d, k, f -> d
    | d is Dict k v
    | f is v -> v
    | k supports Hashing, Equating
    | v supports Modulating
update = \dict key value  -> ...

I'm not sure it improves readability, but I like it better than the one-argument-per-line style

view this post on Zulip Zeljko Nesic (Mar 19 2022 at 12:52):

Kevin Gillette said:

When using types which require abilities (as Dict may require Hashing and Equating), do those need to be spelled out if the function is not using them directly? Can Roc accurately infer required abilities even if they're not declared?

Yes, that should be derived.

Abilities need to be specified if you are using type variable and somewhere inside the expression you are using some of the ability functions or someother function which specifies that you need to have certain abilities, then you also need to spell out those abilities in your definition, if you are using type variables.

view this post on Zulip jan kili (Mar 19 2022 at 13:17):

Thanks for poking at this syntax @Zeljko Nesic! The "add newlines" syntax in @Brendan Hansknecht's latest post looks great, and most importantly I don't want to replace supports with a symbol. Since the ability syntax might be read by noobs even more often than by experts, it should prioritize clarity over terseness (even if that costs us a reserved word).

view this post on Zulip Richard Feldman (Apr 15 2023 at 01:50):

ok, here is a concrete proposal for what syntax to try next:

Abilities in type annotations

Today

Dict.insert : Dict k v, k, v -> Dict k v
    | k has Hash & Eq

Proposed

Dict.insert : Dict k v, k, v -> Dict k v
    where k implements Hash & Eq

view this post on Zulip Richard Feldman (Apr 15 2023 at 01:51):

Defining new Abilities

Today

## Definition of the [DecoderFormatting] ability
DecoderFormatting has
    u8 : Decoder U8 fmt | fmt has DecoderFormatting
    u16 : Decoder U16 fmt | fmt has DecoderFormatting
    u32 : Decoder U32 fmt | fmt has DecoderFormatting

Proposed

## Definition of the [DecoderFormatting] ability
DecoderFormatting implements {
    u8 : Decoder U8 fmt where fmt implements DecoderFormatting,
    u16 : Decoder U16 fmt where fmt implements DecoderFormatting,
    u32 : Decoder U32 fmt where fmt implements DecoderFormatting,
}

view this post on Zulip Richard Feldman (Apr 15 2023 at 01:54):

Defining how an opaque type implements Abilities

Today

Json := JsonState has [
         EncoderFormatting {
             u8: encodeU8,
             u16: encodeU16,
         },
         DecoderFormatting {
             u8: decodeU8,
             u16: decodeU16,
         },
     ]

Proposed

Json := JsonState implements [
    EncoderFormatting {
        u8: encodeU8,
        u16: encodeU16,
    },
    DecoderFormatting {
        u8: decodeU8,
        u16: decodeU16,
    },
]

view this post on Zulip Richard Feldman (Apr 15 2023 at 02:01):

I think we should try this because:

view this post on Zulip Richard Feldman (Apr 15 2023 at 02:13):

I also prefer implements over supports (the runner-up) because I don't like how this reads:

MyOpaqueType := [Foo, Bar Baz] supports { Hash { hash : ... } }

it suggests that it's about to provide a complete list of operations the opaque type supports, but that's inaccurate - the complete list of operations the opaque type supports includes whatever functions this module exposes which involve that type!

in contrast:

MyOpaqueType := [Foo, Bar Baz] implements { Hash { hash : ... } }

I'm not sure why, but this to me feels more additive - like "hey it implements these things, but other implementations may exist too" whereas "supports" feels more exhaustive - like "this is everything it supports"

view this post on Zulip Richard Feldman (Apr 15 2023 at 02:25):

what are peoples' thoughts on this specific design? How would you feel about our adopting it? Anything you'd change?

(keep in mind that we've already had a ton of discussion about this, so I'd like to avoid having the perfect be the enemy of the good since there's a strong consensus that the status quo isn't good, and if we want to change it we do actually have to pick a specific design to change it to!)

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:00):

I think this reads much more naturally. I would be a little sad to lose where to the language but that’s nbd.

view this post on Zulip Brendan Hansknecht (Apr 15 2023 at 03:01):

I like it, though I would argue that in some classes of problems it would be pretty common to use types with abilities, so it would be quite common to see where ... implements ... in type signatures. You might even see it in every function in a file. So if we care about verbosity, i think implements is the wrong choice.....all that a said, i prefer implements and the added verbosity.

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:01):

oh where would only be used in type variables - unlike implements, it doesn't appear in value definitions

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:01):

like DecoderFormatting implements { ... } means that implements has to be a reserved name for identifiers in general (since otherwise it would look to the parser like the beginning of a pattern match on a tag named DecoderFormatting), but since where only appears in type annotations, the only restriction we need there is that you can't choose where as the name for a type variable

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:02):

Ah ok, that’s great

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:04):

Richard Feldman said:

I think this is easiest to justify change. :100:

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:06):

Could we do this?

Dict.insert : Dict k v, k, v -> Dict k v
    where k implements [ Hash, Eq ]

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:07):

we could, but it's most common to have exactly 1 ability restriction like that

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:07):

in fact Dict and Set are the only examples I can think of that use more than one! :big_smile:

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:07):

so then I'd expect all the others to have implements [Eq]

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:08):

which would seem a little unnecessary to me, but maybe not?

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:08):

Well, I could imagine a lot of things having something like Show as well

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:08):

functions having that restriction? :thinking:

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:08):

that would surprise me, honestly

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:09):

Sorry, nvm I was thinking about types

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:09):

ahh gotcha!

view this post on Zulip Richard Feldman (Apr 15 2023 at 03:09):

yeah there we do use braces, because it's definitely the norm to have more than 1 :laughing:

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:10):

There might a point about uniformity there

view this post on Zulip Agus Zubiaga (Apr 15 2023 at 03:10):

but yeah, I guess & is fine for restrictions

view this post on Zulip Bryce Miller (Apr 15 2023 at 04:00):

I also prefer the clarity of your suggested syntax over the brevity of the alternatives.

If verbosity becomes a legitimate issue, I wonder if we couldn’t get around it using the editor instead of using less clear syntax. Perhaps an option or a plugin that collapses the words to symbols. Or maybe an optional mode that only shows type annotations on hover. Not sure either of those are good ideas, but maybe there’s something along those lines to help with verbosity if it’s a concern. Even if Roc was meant to be edited with a normal text editor though, I think I’d still prefer the clearer syntax.

view this post on Zulip Luke Boswell (Apr 15 2023 at 06:26):

I like it. :+1:

view this post on Zulip Anton (Apr 15 2023 at 07:44):

I wonder if we couldn’t get around it using the editor instead of using less clear syntax

Yeah, there's been several cases where I imagined it would be nice to have a view plugin to display code nicely organized/transformed according to your personal preferences.

view this post on Zulip Rene Mailaender (Apr 15 2023 at 10:57):

I really like the new syntax. i would expect abilities to be used most of the time in packages and platforms and therefore been read more often than written. (of course i might be wrong here) so i would prefere a verbose but clear syntax over a concise one, that would require you to "learn" it first, before you can read it.
I bet even someone who is new to the language and / or hase never worked with abilities before, would have at least a general idea, what where k implements Stuff means immediately.

view this post on Zulip Rene Mailaender (Apr 15 2023 at 11:06):

although | is more concise than when, some have found it harder to read and I'd like to try out the more verbose but explicit way and see how it feels in comparison to the current | syntax.

at least for this reads a lot clearer. i'm quite new to writing roc and the | syntax always confused me a little. in my head it always read like a weird Or-statement at first and i had to decompose it, to understand it. meanwhile the where syntax reads a lot clearer for me. and i don't have to think about it really.


Last updated: Jun 16 2026 at 16:19 UTC