One piece of syntax that confused me a little when reading through the tutorial is the record shorthand syntax. Record shorthand syntax is where when you define a function that takes a record and returns a field, you can just write.fieldname:
returnFoo = .foo
returnFoo
# { foo : a }* -> a
returnFoo { foo: "hi!", bar: "blah" }
# hi!
It can also be used inline:
capitalizeField = \record, toField ->
record
|> toField
|> Str.capitalize
baz = { foo: "hi!", bar: "blah" }
baz
|> capitalizeField .foo
However, to me, upon first meeting this shorthand syntax it wasn't clear to me that .foo should be a function, since to my knowledge there was only one way to create a function in Roc: with a backslash (this was mentioned in "A taste of Roc" I think).
I come from Swift, so I'm biased here. Swift has a very similar syntax for making "property access" into a function, called keypath notation, which looks like: \.fieldname. I know it's just a backslash, but in Roc terms it makes it instantly recognizable as a function. It also creates a nicer visual seperation between the function this is being passed into and itself:
baz
|> capitalizeField \.foo
Ergonomically and semantically this feels much more natural to me. What do you think?
P.S: I know there's actually a third way to create a function in Roc, using tags with payloads. Could a case be made that those should require a backslash too? I'm not sure, and I feel like that's probably out of scope.
Sounds pretty reasonable, though it feels like you started writing a lambda but didn't finish: \.foo feels like it should be followed with -> #do something with foo.
But that is just my initial reading bias. I don't really think .foo alone is any better in terms of being a reasonable syntax.
Interesting – to me the dot makes it clear that this is a function only interested in accessing a record's field, and that's it. I guess it could be just me being used to Swift keypaths.
What does everyone else think? Would this be a net positive, or would it just add visual clutter?
PureScript uses the syntax _.foo for this
and so does Scala
at least Scala supports (and I think PureScripts supports it too) using _ for arbitrary partial application
e.g. if Roc had that, you could do List.map (Str.concat _ "!!!") strings
and _.foo would be consistent with that
I'm not sure whether that "underscore for partial application" feature would be a net positive or a net negative for Roc, but if we someday did do that, then _.foo would be consistent with that
I have the same reaction as @Brendan Hansknecht , the \.foo looks unfinished to me because it's missing an arrow. Or the body of the function is where the argument should be, or something!
@Nikita Mounier it's interesting, I have a different mental model of this. You describe it as a "shorthand syntax" whereas I think of it as a "special function name", not a syntax. It's a function that is automatically made available whenever you make a record. So maybe there is in fact one "other way to create a function"!
I like the idea of being able to use some character or keyword for partial application, whether it's _ or something else
One thing confuses me now:
Foo : { baz : Str }
Oof : { baz : Int }
To which field .baz refers to?
i wonder if then \.{a, b} would desugar into \{a, b} -> {a, b}, and more generally whether some forms of destructing would be usable via shorthand.
To which field .baz refers to?
Either one!
.baz
# Prints: { baz: a }* -> a
This means that it takes any record which has at least a field called baz of any type, and it'll return a value of that type – namely the value stored in the baz field. So if you apple .baz to Foo, it'll return the string, and if you apply .baz to Oof, it'll return the int.
This is why the model of .baz simply being a function that takes any record that has a certain field and spits back out that field really helps me – and why making it look syntactically closer to function declarations seems like the right step.
Kevin Gillette said:
i wonder if then
\.{a, b}would desugar into\{a, b} -> {a, b}, and more generally whether some forms of destructing would be usable via shorthand.
Yeah, that's a really interesting idea!
If issue #2695 – Anonymous record update syntax gets implemented I actually think it could pair nicely with backslash syntax for consistency – \&foo desugars to \record, val -> { record & foo: val }
Nikita Mounier said:
If issue #2695 – Anonymous record update syntax gets implemented I actually think it could pair nicely with backslash syntax for consistency –
\&foodesugars to\record, val -> { record & foo: val }
I don't understand how that works. Can you give a definition of foo, and then an example of a full expression using \&foo and what the result of evaluating it would be?
Syntactic sugar seems to usually be a simple syntactic transform, but this seems to be contextually dependent on the nature of foo?
The original context for this was something like
onClick = \state -> { state & clicks: state.clicks + 1 }
which would become
onClick = \state -> &clicks state (state.clicks + 1)
@Ayaz Hafiz I have little difficulty reading the original (unsugared) form, but a much harder time reading the &clicks syntax. Would that even be nestable (using multiple &x forms together in the same expression)?
I could see \&.clicks + 1 making more sense, but is it so valuable and so often needed that we'd want to introduce a hard-to-google-for \&. syntax that would almost certainly scare off some potential newcomers?
Last updated: Jun 16 2026 at 16:19 UTC