here's an example of how the homepage could look with a static dispatch example, using all the syntax we've been talking about recently:
this example would be inefficient today, but would be totally efficient with #ideas > Iterators and fusion proposal - so could work as a cool example of Fast in the future
this example demonstrates:
keep_if over filterso a mix of things that will probably be familiar to beginners as well as some things that are unfamiliar but hopefully intriguing :big_smile:
(but nothing that looks too far out there, such that overall it hopefully still gives the impression of "ok I can follow this")
regarding the idea of this someday being the homepage example - any thoughts and feedback welcome!
Looks nice, though I don’t know how often people will use bare records these days, with static dispatch pushing people towards opaque types. What would it look like if there was an opaque Artist type involved?
opaque records still have normal fields too, but even setting that aside, I expect structural records will still see lots of use :big_smile:
I think the goal of an initial snippet is to concisely give people a taste of what the language looks like, and it should be a mix of familiar and intriguing - but not intimidating
if it looks too alien, some readers will click away thinking "this is too far out there; I'm never going to use this language"
but if it's 100% familiar, with nothing novel, then some readers will click away thinking "this is just ______, and I already know that language"
so the goal is to have a mix, to motivate people to continue reading past that first impression and invest their time in reading some actual paragraphs :big_smile:
anyway, the reason I bring all that up is that I don't think making Artist an opaque type would help with those goals
I think I'd prefer to have artists formatted on its own line. Having the functions indented less than artists makes it look a bit off to me.
"starring" artists is not the most familiar thing. Using a familiar transformation will likely lead to a better impression of Roc for the reader. For example, liking posts would be very familiar but that can evoke negaitve feelings about social media so not that :p
Claude can probably provide some more familiar suggestions.
I think the artist thing may have come from Roc(k) being a music genre
I think it's good from a theming/teaching perspective to lean into certain metaphors/aesthetics
Rock is a good one to do
Yeah, using artists is fine, it's just the "starring"
.keep_if(.rocks)
Maybe I've missed some updates, but wouldn't it either be .keep_if(is_starred) or .keep_if(.is_starred()) instead of .keep_if(.is_starred)?
The artist in this example would have a is_starred field. The .keep_if(.is_starred) is a shortcut for .keep_if(|a| a.is_starred).
Ahh, I see, thanks. I thought is_starred was a predicate not a field there.
maybe is_active?
and then a bullet point emoji instead of a star emoji
(er, unicode character, not emoji)
What doe an "active artist" mean :p ? "followed artists" seems intuitive
Active, as in still making music
Could also do is_soloist or something with genre
Yeah, genre could be very familiar, we could go with songs and is_hard_rock
.plays_music
Is not having a is_active field a case of boolean blindness. I remember from the tutorial that using bool is not the Roc way? So having such field as the first example might not be the way?
Hah, good point
is_active is a function actually
https://www.roc-lang.org/builtins/List#keepIf
.keep_if(|song| song.genre == Rock)
.keep_if(.genre.eq(Rock))
yeah we could do something like .genre.equals(Rock), although I don't think it's 100% sure we'll end up doing the "method accessor" part of the proposal
(it got mixed feedback at the time)
so for now I'd like to stick with something we already have, namely field accessors
but I do want to do an accessor on that line, since the point of that line is to show a feature you find in Roc but wouldn't find in a mainstream language
whereas .keep_if(|song| song.genre == Rock) would mostly be showing similar things to the next line (since a reader wouldn't realize the implications of Rock being a tag in a tag union given that they've only seen Roc code for about a second at that point)
how about is_favorite? I also like keeping it positive and broadly relatable (who doesn't have a set of favorite artists in some genre?)
although I guess now I've chosen a word with a different spelling in American vs British English :laughing:
although I actually think it would be low-key hilarious to quietly internationalize (or internationalise, if you prefer) behind the scenes so it displays asfavourites if that's how it would be spelled in the viewer's locale :big_smile:
a related idea is to demonstrate right up front "hey this is a functional language that is awesome at I/O"
hm, also - should those be indented? :thinking:
It's good that File is 4 letters to make indentation line up! I really like that it includes:
And all the other stuff
I don't even know what features are missing at this point...
But actually, anonymous tag unions were my first big selling point for Roc
Not sure how to demo that in like 3 lines of code :thinking:
I mean, you kind of are with the ?. But it’s not exactly clear that’s the case
might be a big much for one example :sweat_smile:
As much as I like what I see because I want safety in programming languages and this shows that, I think the problem is that 1 of 3 "active" lines is dedicated to error handling
And people want something cool, so we can show that early in a tutorial, but probably should avoid it with the very first thing people see
my bigger concern with it is just that you really can't tell what's cool about it at a glance
it needs explanation
whereas I think .keep_if(.is_favorite) can be figured out without explanation
And plus mapErr will just be ? Binop soon
I’m doing that after the ?? Binop
oh yeah we should revisit the ? BinOp in the context of parens-and-commas and the ? suffix
or wait, did the BinOp imply the suffix too? :thinking:
like would foo() ? Bar desugar to foo().map_err(Bar)? or to something else?
I think ? Would be used with try keyword, but you are right
It would be funky I think with the postfix ?
I kinda like the idea of it doing the early return for you
so foo() ? bar would desugar to
when foo() is
Ok val -> val
Err err -> return bar(err)
and if you don't want the early return, you can just use .map_err
so this would make the most common case the most concise
plus I like that single ? always means "an early return is happening here"
2 questions about this syntax. If you want to map to and return a constant error, the syntax would become foo() ? |_| ConstantErr?
Second:
How would this be used in pipes?
foo =
bar() ? BarErr
.baz()
Something like this?
Or would there need to be parens around the line with ??
hm, good point about pipes
yeah I think you'd need parens
or to use .map_err
Richard Feldman said:
so
foo() ? barwould desugar towhen foo() is Ok val -> val Err err -> return bar(err)
Super here for this, as it preserves that "make error tracing so easy it's brainless" thing I want
Richard Feldman said:
yeah I think you'd need parens
In a longer pipe that might become more verbose
With parens:
(
foo1()
.foo2)
.foo3() ? MapErr
)
.bar()
.baz()
Without parens:
foo1()
.foo2()
.foo3() ? MapErr
.bar()
.baz()
With map_err and postfix ?:
foo1()
.foo2()
.foo3()
.map_err(MapErr)?
.bar()
.baz()
yeah maybe it's fine to just use map_err in pipes
When I see ?. it makes me want short circuiting (returning the Err tag) for that expression.... That's probably just the Javascripter in me though
a related idea is to demonstrate right up front "hey this is a functional language that is awesome at I/O"
One concern I have with this example is that it has a lot of symbols ? | ! . $ {} ★. This may lead people to think that Roc is an operator soup language.
The ★ in the example is just part of a string :grinning_face_with_smiling_eyes:
With the exception of ? these symbols are all used on mainstream languages though.
. is used in most languages.
! suffix is used in Ruby for dangerous functions. (convention)
? suffix is used in Ruby/Elixir for functions that return bool. (convention)
${} is the exact same syntax as JS so most people will be instantly familiar with it.
| | is used in Rust (ok, not so mainstream)
My only concern with the example above is the map_err(..)? - for me this can be read in multiple different ways based on other language conventions. Is it returning a bool like Ruby/Elixir? Is it conditional-chaining like JS? And, in my perspective, it is just another function with no extra meaning.
The map_err(..)? signals to Rust devs that we do error handling just like they do
Georges Boris said:
| |is used in Rust (ok, not so mainstream)
I think Rust got this from Ruby. Also Rust is rapidly becoming mainstream!
Ruby is pretty mainstream though! And Ruby got it from Smalltalk (ok, really not mainstream....but there is history to it!)
I didn't know Smalltalk used that lambda syntax!
Yeah they call them blocks
I did Exercism last year in Pharo(a smalltalk variant)
Only reason I know
Actually, technically it's how you introduce locals in a function: https://en.wikipedia.org/wiki/Smalltalk#Variable_declarations
Code blocks are actually like [ :argName | body ]
https://en.wikipedia.org/wiki/Smalltalk#Code_blocks
The
★in the example is just part of a string
Yeah, I did notice that but it may contribute to the impression that there are a lot of symbols in the snippet
@Sam Mohr but isn't the map_error type enough to tell that? What extra meaning is it getting from the ? ?
I mean - if I created another function that worked on a result, both on the Ok and Err variants, would that also be flagged with ? . I thought the ? in Rust worked as "this may fail, so everything from here on out will only work on the Ok branch.
That is what it means both in Rust and in this example. It's also a return point if the Err branch is taken.
@Georges Boris yes, the ? means "early return if this is an Err"
It's not like Ruby where it means "this returns a boolean since it looks like a question". The tell is that the ? is after the args, not at the end of the name
Ohh - I was reading all functions as map over the result type.
So in this scenario the static dispatch would be based on the Ok type of the result? :thinking:
fetch_user_post_titles : UserId -> Result (List Str) [UserNotFound, QueryError]_
fetch_user_post_titles = | user_id |
fetch_user!(user_id)
.fetch_posts!()
.map(.title)
Is the static dispatch handling results in a special way like in the function above? Or would I need to:
fetch_user_post_titles : UserId -> Result (List Str) [UserNotFound, QueryError]_
fetch_user_post_titles = | user_id |
fetch_user!(user_id)
.then(.fetch_posts!())
.map(.map(.title))
Your first example wouldn't compile unless Result.fetch_posts! exists. If User.fetch_posts! exists the code would be fetch_user!(user_id)?.fetch_posts!()?.map(.title) or if fetch_posts! is a function in the namespace it'd be fetch_user!(user_id)?.pass_to(fetch_posts!)?.map(.title). The ? unwraps on Ok and returns on Err.
Now I get it! Thanks
I hate it
Lol joking - but ngl the ? is really easy to miss for such an important control flow
It originally existed in Rust as the try! macro but that got replaced by ? for convenience because it's the default error handling strategy so you get used to tacking it on to any fallible operation.
I like it because it keeps error handling pretty close to the convenience of exceptions but you don't get surprise exceptions at runtime.
Yes, you use it so much that you want it to be terse
yeah it's one of the features that's unique to Rust where after using it for awhile my reaction is "I want this in every language" :big_smile:
Good thing Roc will eventually consume the usage of every other language
Got it - if it is already tried and true then no reason to debate it :blush:
My thoughts were less about it being ? and more related to it being a single chatacter suffix:
foo(xxx)
.foobaz(xyz)
.bar!(ykz)?
.foofoo()
.barbaz(xyy)
.bazzab(yz)?
.gugu()
found a super concise one that I like:
urls = ids.map(|id| "/songs/${id}")
only downside is it doesn't show effectual functions
yeah
It's the same line you'd write in many languages:
let urls = ids.map(id => "/songs/${id}")
let urls = ids.map(|id| format!("/songs/{id}"))
var urls = ids.Select(id => $"/songs/{id}")
I've been hanging around long enough to have a pretty good idea of what it means to you but putting on my uncharitable novice hat it gets a "why did they even pick that?". The extra ceremony on the current home page example lets me know that I'm dealing with a Haskell family language while this is just unremarkable.
yeah it's a reasonable point, although the word right before that code snippet is the language self-describing as "functional" - and the only languages I know of where this sort of syntax would be valid are either procedural, OO, or hybrid OO-FP (I'm thinking specifically of F# and Scala)
so my hope with this example would be that someone thinks "it's a functional language that looks very familiar to me"
so what this example doesn't do in comparison to other options is that it doesn't have something intriguing like the !
this would show ! and static dispatch in one line:
text = File.read_utf8!(path).trim()
...but that doesn't show lambdas or string interpolation, and isn't an example of functional-style code
in the realm of multiple lines there are more options, e.g. what we discussed earlier - https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/static.20dispatch.20-.20homepage.20example/near/490592897
I guess comparing those side by side, the extra lines do seem significantly more intriguing :thinking:
I prefer a few lines and an effect
Like maybe map song names to real urls then https get each url with an effectful map?
Preferably in parallel, but we don't have a setup for that at the moment
I would also prefer a multiline showcase. Maybe even starting with a simple expect test for the function below. I really like that kind of style, a simple test provides a lot of information quickly compared to your typical doc comment.
Last updated: Jun 16 2026 at 16:19 UTC