Stream: ideas

Topic: static dispatch - homepage example


view this post on Zulip Richard Feldman (Dec 19 2024 at 20:33):

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:

roc-lang.org

view this post on Zulip Richard Feldman (Dec 19 2024 at 20:33):

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

view this post on Zulip Richard Feldman (Dec 19 2024 at 20:37):

this example demonstrates:

view this post on Zulip Richard Feldman (Dec 19 2024 at 20:43):

so a mix of things that will probably be familiar to beginners as well as some things that are unfamiliar but hopefully intriguing :big_smile:

view this post on Zulip Richard Feldman (Dec 19 2024 at 20:43):

(but nothing that looks too far out there, such that overall it hopefully still gives the impression of "ok I can follow this")

view this post on Zulip Richard Feldman (Dec 19 2024 at 20:47):

regarding the idea of this someday being the homepage example - any thoughts and feedback welcome!

view this post on Zulip Kasper Møller Andersen (Dec 19 2024 at 21:02):

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?

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:15):

opaque records still have normal fields too, but even setting that aside, I expect structural records will still see lots of use :big_smile:

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:16):

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

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:21):

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"

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:22):

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"

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:23):

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:

view this post on Zulip Richard Feldman (Dec 19 2024 at 21:24):

anyway, the reason I bring all that up is that I don't think making Artist an opaque type would help with those goals

view this post on Zulip Anton (Dec 20 2024 at 11:31):

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.

view this post on Zulip Anton (Dec 20 2024 at 11:36):

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

view this post on Zulip Sam Mohr (Dec 20 2024 at 12:32):

I think the artist thing may have come from Roc(k) being a music genre

view this post on Zulip Sam Mohr (Dec 20 2024 at 12:33):

I think it's good from a theming/teaching perspective to lean into certain metaphors/aesthetics

view this post on Zulip Sam Mohr (Dec 20 2024 at 12:33):

Rock is a good one to do

view this post on Zulip Anton (Dec 20 2024 at 12:41):

Yeah, using artists is fine, it's just the "starring"

view this post on Zulip Agus Zubiaga (Dec 20 2024 at 12:44):

.keep_if(.rocks)

view this post on Zulip Isaac Van Doren (Dec 20 2024 at 17:22):

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

view this post on Zulip Karl (Dec 20 2024 at 17:28):

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

view this post on Zulip Isaac Van Doren (Dec 20 2024 at 17:30):

Ahh, I see, thanks. I thought is_starred was a predicate not a field there.

view this post on Zulip Richard Feldman (Dec 20 2024 at 17:34):

maybe is_active?

view this post on Zulip Richard Feldman (Dec 20 2024 at 17:34):

and then a bullet point emoji instead of a star emoji

view this post on Zulip Richard Feldman (Dec 20 2024 at 17:34):

(er, unicode character, not emoji)

view this post on Zulip Anton (Dec 20 2024 at 18:02):

What doe an "active artist" mean :p ? "followed artists" seems intuitive

view this post on Zulip Brendan Hansknecht (Dec 20 2024 at 18:28):

Active, as in still making music

view this post on Zulip Brendan Hansknecht (Dec 20 2024 at 18:29):

Could also do is_soloist or something with genre

view this post on Zulip Anton (Dec 20 2024 at 18:32):

Yeah, genre could be very familiar, we could go with songs and is_hard_rock

view this post on Zulip Luke Boswell (Dec 20 2024 at 18:35):

.plays_music

view this post on Zulip Henrik Larsson (Dec 20 2024 at 18:37):

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?

view this post on Zulip Anton (Dec 20 2024 at 18:41):

Hah, good point

view this post on Zulip Anton (Dec 20 2024 at 18:44):

is_active is a function actually

view this post on Zulip Anton (Dec 20 2024 at 18:45):

https://www.roc-lang.org/builtins/List#keepIf

view this post on Zulip Brendan Hansknecht (Dec 20 2024 at 18:53):

.keep_if(|song| song.genre == Rock)

view this post on Zulip Isaac Van Doren (Dec 20 2024 at 19:23):

.keep_if(.genre.eq(Rock))

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:13):

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

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:13):

(it got mixed feedback at the time)

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:13):

so for now I'd like to stick with something we already have, namely field accessors

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:15):

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

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:16):

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)

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:18):

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

homepage-favorite.png

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:19):

although I guess now I've chosen a word with a different spelling in American vs British English :laughing:

view this post on Zulip Richard Feldman (Dec 20 2024 at 20:20):

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:

view this post on Zulip Richard Feldman (Dec 23 2024 at 21:52):

a related idea is to demonstrate right up front "hey this is a functional language that is awesome at I/O"

homepage-example.png

view this post on Zulip Richard Feldman (Dec 23 2024 at 21:57):

hm, also - should those be indented? :thinking:

indented

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:08):

It's good that File is 4 letters to make indentation line up! I really like that it includes:

And all the other stuff

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:09):

I don't even know what features are missing at this point...

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:09):

But actually, anonymous tag unions were my first big selling point for Roc

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:09):

Not sure how to demo that in like 3 lines of code :thinking:

view this post on Zulip Anthony Bullard (Dec 23 2024 at 22:12):

I mean, you kind of are with the ?. But it’s not exactly clear that’s the case

view this post on Zulip Richard Feldman (Dec 23 2024 at 22:24):

might be a big much for one example :sweat_smile:

tags

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:26):

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

view this post on Zulip Sam Mohr (Dec 23 2024 at 22:27):

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

view this post on Zulip Richard Feldman (Dec 23 2024 at 22:36):

my bigger concern with it is just that you really can't tell what's cool about it at a glance

view this post on Zulip Richard Feldman (Dec 23 2024 at 22:36):

it needs explanation

view this post on Zulip Richard Feldman (Dec 23 2024 at 22:37):

whereas I think .keep_if(.is_favorite) can be figured out without explanation

view this post on Zulip Anthony Bullard (Dec 23 2024 at 22:44):

And plus mapErr will just be ? Binop soon

view this post on Zulip Anthony Bullard (Dec 23 2024 at 22:44):

I’m doing that after the ?? Binop

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:05):

oh yeah we should revisit the ? BinOp in the context of parens-and-commas and the ? suffix

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:06):

or wait, did the BinOp imply the suffix too? :thinking:

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:06):

like would foo() ? Bar desugar to foo().map_err(Bar)? or to something else?

view this post on Zulip Anthony Bullard (Dec 23 2024 at 23:13):

I think ? Would be used with try keyword, but you are right

view this post on Zulip Anthony Bullard (Dec 23 2024 at 23:14):

It would be funky I think with the postfix ?

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:17):

I kinda like the idea of it doing the early return for you

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:18):

so foo() ? bar would desugar to

when foo() is
    Ok val -> val
    Err err -> return bar(err)

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:19):

and if you don't want the early return, you can just use .map_err

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:19):

so this would make the most common case the most concise

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:19):

plus I like that single ? always means "an early return is happening here"

view this post on Zulip Kilian Vounckx (Dec 23 2024 at 23:21):

2 questions about this syntax. If you want to map to and return a constant error, the syntax would become foo() ? |_| ConstantErr?

view this post on Zulip Kilian Vounckx (Dec 23 2024 at 23:22):

Second:
How would this be used in pipes?

foo =
    bar() ? BarErr
    .baz()

Something like this?

view this post on Zulip Kilian Vounckx (Dec 23 2024 at 23:22):

Or would there need to be parens around the line with ??

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:23):

hm, good point about pipes

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:23):

yeah I think you'd need parens

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:23):

or to use .map_err

view this post on Zulip Sam Mohr (Dec 23 2024 at 23:26):

Richard Feldman said:

so foo() ? bar would desugar to

when 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

view this post on Zulip Kilian Vounckx (Dec 23 2024 at 23:27):

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

view this post on Zulip Richard Feldman (Dec 23 2024 at 23:35):

yeah maybe it's fine to just use map_err in pipes

view this post on Zulip Anthony Bullard (Dec 24 2024 at 00:57):

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

view this post on Zulip Anton (Dec 27 2024 at 11:42):

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.

view this post on Zulip Georges Boris (Dec 27 2024 at 15:45):

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.

view this post on Zulip Sam Mohr (Dec 27 2024 at 15:47):

The map_err(..)? signals to Rust devs that we do error handling just like they do

view this post on Zulip Richard Feldman (Dec 27 2024 at 15:54):

Georges Boris said:

| | is used in Rust (ok, not so mainstream)

I think Rust got this from Ruby. Also Rust is rapidly becoming mainstream!

view this post on Zulip Anthony Bullard (Dec 27 2024 at 15:59):

Ruby is pretty mainstream though! And Ruby got it from Smalltalk (ok, really not mainstream....but there is history to it!)

view this post on Zulip Richard Feldman (Dec 27 2024 at 16:02):

I didn't know Smalltalk used that lambda syntax!

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:02):

Yeah they call them blocks

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:02):

I did Exercism last year in Pharo(a smalltalk variant)

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:02):

Only reason I know

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:04):

Actually, technically it's how you introduce locals in a function: https://en.wikipedia.org/wiki/Smalltalk#Variable_declarations

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:05):

Code blocks are actually like [ :argName | body ]

view this post on Zulip Anthony Bullard (Dec 27 2024 at 16:05):

https://en.wikipedia.org/wiki/Smalltalk#Code_blocks

view this post on Zulip Anton (Dec 27 2024 at 16:07):

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

view this post on Zulip Georges Boris (Dec 27 2024 at 16:08):

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

view this post on Zulip Karl (Dec 27 2024 at 16:10):

That is what it means both in Rust and in this example. It's also a return point if the Err branch is taken.

view this post on Zulip Sam Mohr (Dec 27 2024 at 16:12):

@Georges Boris yes, the ? means "early return if this is an Err"

view this post on Zulip Sam Mohr (Dec 27 2024 at 16:13):

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

view this post on Zulip Georges Boris (Dec 27 2024 at 16:19):

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

view this post on Zulip Karl (Dec 27 2024 at 16:35):

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.

view this post on Zulip Georges Boris (Dec 27 2024 at 16:45):

Now I get it! Thanks

view this post on Zulip Georges Boris (Dec 27 2024 at 16:46):

I hate it

view this post on Zulip Georges Boris (Dec 27 2024 at 16:47):

Lol joking - but ngl the ? is really easy to miss for such an important control flow

view this post on Zulip Karl (Dec 27 2024 at 16:54):

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.

view this post on Zulip Karl (Dec 27 2024 at 16:55):

I like it because it keeps error handling pretty close to the convenience of exceptions but you don't get surprise exceptions at runtime.

view this post on Zulip Sam Mohr (Dec 27 2024 at 16:55):

Yes, you use it so much that you want it to be terse

view this post on Zulip Richard Feldman (Dec 27 2024 at 17:22):

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:

view this post on Zulip Sam Mohr (Dec 27 2024 at 17:23):

Good thing Roc will eventually consume the usage of every other language

view this post on Zulip Georges Boris (Dec 27 2024 at 17:29):

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

view this post on Zulip Richard Feldman (Jun 22 2025 at 18:04):

found a super concise one that I like:

urls = ids.map(|id| "/songs/${id}")

desktop
mobile

view this post on Zulip Richard Feldman (Jun 22 2025 at 18:05):

view this post on Zulip Anthony Bullard (Jun 22 2025 at 18:43):

only downside is it doesn't show effectual functions

view this post on Zulip Richard Feldman (Jun 22 2025 at 18:52):

yeah

view this post on Zulip Karl (Jun 22 2025 at 20:19):

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.

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:38):

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)

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:39):

so my hope with this example would be that someone thinks "it's a functional language that looks very familiar to me"

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:40):

so what this example doesn't do in comparison to other options is that it doesn't have something intriguing like the !

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:47):

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

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:51):

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

view this post on Zulip Richard Feldman (Jun 22 2025 at 20:53):

I guess comparing those side by side, the extra lines do seem significantly more intriguing :thinking:

view this post on Zulip Brendan Hansknecht (Jun 22 2025 at 22:26):

I prefer a few lines and an effect

view this post on Zulip Brendan Hansknecht (Jun 22 2025 at 22:27):

Like maybe map song names to real urls then https get each url with an effectful map?

view this post on Zulip Brendan Hansknecht (Jun 22 2025 at 22:27):

Preferably in parallel, but we don't have a setup for that at the moment

view this post on Zulip Anton (Jun 23 2025 at 10:16):

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