this article by @matklad gave me a random idea I wanted to write down (I'm not actually proposing it per se, just think it's an interesting idea):
something we've talked about before as a motivation for shadowing (e.g. in #ideas > Shadowing & Redeclaration) is this pattern, which comes up sometimes:
\list ->
list2 = List.set list index1 "blah"
list3 = List.set list2 index2 "blah"
List.set list3 index3 "blah"
so the idea is to have syntax sugar for this pattern, such that you could write this:
\list ->
List.set! list index1 "blah"
List.set! list index2 "blah"
List.set list index3 "blah"
in general the pattern would be: fn! x arg2 arg3 desugars to x = fn x arg2 arg3
so to use it, you would have to call the function passing only an identifier (e.g. x or list) as its first argument; otherwise, syntax error
and then that identifier would be assigned to the value returned by the function call
an interesting question is: does this still have the downsides of general shadowing?
I haven't really thought about it (this is just an idle thought I'm sharing because I think it's interesting) but it seems like it probably has some of the downsides but not all of the downsides, because it's a limited form of it
some things I think are interesting about the idea:
foo which returns a new value and then a separate function named foo! which mutates in-place; this is sort of like that except there's just one function, and there's defensive cloning built in based on uniquenessx = ... followed by x2 = ... and then x3 = ... etcI haven't given any serious thought to whether it might actually a good idea in Roc, but I do think it's interesting to think about at least!
a downside that comes to mind is that it could be confusing from a performance perspective, because it looks like it's mutating in-place but really that's not a guarantee
My first thought is that if I understand right, this syntax sugar wouldn't be much more flexible than pipelining, since it only allows the x = f x ... pattern. This wouldn't allow you to rewrite y = f x y or {x, a} = f x. For example, would there any way to use this syntax sugar for the example given in the thread linked above?
toIdParserList : IdBindState, List Parser -> { state : IdBindState, ids : List Id }
toIdParserList = \state, parsers ->
List.walk parsers { state, ids: [] } \{ state: state2, ids }, parser ->
{ state: newState2, id } = toIdParser state parser
{ state: newState2, ids: List.append ids id }
But I do find it interesting. I've always thought it would be cool if Ruby's foo! convention was just syntax sugar.
I don't think it would help in that example
Yeah, i think where this hurts the most in roc currently is things like the random number generator where it is returning a new state and whatever result you requested. And this doesn't help there.
is there any benefit of something like this over a pipeline apart from being more familiar to someone used to imperative/mutable programming?
I was thinking the same. Other functional languages solve this by using pipelines.
Yeah, it does seem like pipelining would be the best solution for cases like this. The ! syntax seems very unintuitive to me.
Last updated: Jun 16 2026 at 16:19 UTC