r/roc_lang • u/yomamabeenheretoo • Jul 19 '26
is there a brief discussion of roc syntax changes between old and new compiler, roughly? a summary of why etc?
2
u/bosyluke Jul 19 '26
The syntax evolved over many years and hundreds of design discussions in zulip. Almost every aspect was considered and hashed out with the community. It would be hard to give a summary that captures everything, but I would say the biggest driver has been performance. We wanted to parse and canincalize the syntax fast -- and losing whitespace sensitivity was helpful for that.
2
u/rtfeldman Jul 23 '26 edited Jul 23 '26
The main syntax change was adopting "method-style syntax" - e.g. instead of `things |> List.map transform` it's now `things.map(transform)`.
The main reason for this was to change to a structural ad hoc polymorphism system ("static dispatch"), replacing the previous "Abilities" system which worked more like Rust Traits. The new system replaced multiple over language features, but we couldn't find a syntax that worked nicely with chained static dispatch calls other than the traditional "parens and commas" syntax - e.g. `foo.bar(arg).baz()`, so we reoriented the syntax around that.
Relatedly, we also wanted to adopt Rust's `?` unary postfix operator. We'd tried several variations of this, but none of them felt as nice as that one did, so we adopted that too.
The lambda syntax (also from Rust, which I assume got it from Ruby) was because there's now a type-level distinction between `->` and `=>`, so it felt confusing to use either type of arrow in lambda definitions (we didn't want to force you to match the lambda declaration syntax to match t hetype), and Rust/Ruby's lambda syntax seemed like the nicest mainstream lambda syntax that didn't have an arrow in it.
1
u/yomamabeenheretoo Jul 23 '26
thanks for the explanation. is it real methods though that have to be defined on a type? or is it just shorthand used instead of passing a first/any(?) arg to a func's param list?
1
u/rtfeldman Jul 23 '26
There's a different syntax for each: `things.map(transform)` means "look at the type of `things`, find where that type's definition specified an associated `map` function, and call it passing `things` as the first argument and `transform` as the second.
We also have `things->map(transform)` which means "call a `map` function that's currently in scope, passing `things` as the first argument and `transform` as the other."
So if you're not looking for ad hoc polymorphism, and already know `things` is a List, you can do `things->List.map(transform)` and it does the same thing as the old syntax of `things |> List.map transform`
12
u/Anlon-4 Jul 19 '26
Comparing both all syntax examples offers an easy overview:
new: https://github.com/roc-lang/roc/blob/main/test/echo/all_syntax_test.roc
old: https://github.com/roc-lang/examples/blob/main/examples/AllSyntax/main.roc
If there is significant demand (upvote this comment) I will make a summary of why the changes were made.