Now that we have expect, it could be nice to expose a function that checks whether or not a refcounted value is unique. These function would simply check if the refcount is 1.
The main use case would be to help in avoiding copies in a call stack. If each function is able to ensure that it's inputs are unique and is coded in a way as to not duplicate the inputs, the inputs would always get updated inplace. It would help to defend from accidentally keeping a reference to a value and then getting a copy. This is a very common optimization that I manualy perform when trying to improve benchmarks of roc code.
This would not perfectly defend from accidental copies, but it would be a cheap way to easily debug where a copy is happening and when a value is duplicated. What are people's thoughts on adding a isUnique functions?
As an aside, a makeUnique function should probably also be pair with this addition. That way if you have a list that is not unique, you can still pass it into a call stack that expects a unique list. Otherwise, a call stack could always wait until after the first update of a list to start expecting isUnique. That would make it so that the first update would make the list unique and then it would stay unique as long as the programmer didn't mess up.
the first update would make the list unique and then it would stay unique as long as the programmer didn't mess up.
I believe this already happens automatically
like all the functions that can mutate in-place will clone (into a clone that's necessarily unique because we just cloned it!) and then perform their operation
Yes. I am talking about the case where you want to enable your top level function to accept a non-unique list, but want to make sure you only duplicate it once.
So after the first update it will be guarenteed unique due to how Roc works. Then all other uses of the list and functions you call can use expect List.isUnique. They will only crash if you made a bug that duplicated the list by accident. This is more thinking from a library author perspective.
As an auther, you probably want to accept a non-unique list, but you may want to ensure that once you have it, you only ever copy it once across all of your functions. So interspersing expect List.isUnique is kinda a defensive measure/a useful debugging tool.
yeah I can definitely see it being useful as like a "this is true right now, and I want a test to fail if it ever stops being true" measure
and expect is kinda perfect for that because it gets compiled away at runtime, so if there's some code pathway that violates it, but your tests don't catch it, you won't blow up your users' production apps with it; they'll just get more clones than is ideal
Exactly!
I don't know what expect does, but I'm assuming it's the equivalent of the assertmacro in C. Please correct me if I'm wrong.
Would the use of isUnique be restricted so that it would only be possible to use it in conjunction with expect? Otherwise it would be possible to use it to write code that is not referentially transparent. I know it's just an academic concern, but the purist in me is a little bit bothered by that...
Is full referential transparency a design goal for ROC, by the way? Or are minor deviations from it considered acceptable?
I'm totally on board with the idea of adding of a makeUnique function. I definitely see why it would be useful, and it wouldn't affect referential transparency in any way
Expect is just a debug assert. It is removed in release builds
As for referential transparency. That's a good point.
someFunc = \x ->
if List.isUnique x then
7
else
12
x = [ ...]
a = someFunc x
b = someFunc x
Yep, definitely broken. Dang.....
I would be fine with limiting this to being only allowed in an expect. Which still technically breaks referential transparency. First call would panic second would run fine. But it breaks it in an expected way that I would not expect to cause issues.
we could make a separate expect-unique keyword
full referential transparency is definitely a design invariant for Roc! Has been from day one, and I plan for that to never change. :big_smile:
Also, makeUnique should only be added if we also add isUnique or equivalent. It is strictly a pesimization. In fact in release build it could be argued that we should ignore makeUnique like we would with isUnique.
Last updated: Jun 16 2026 at 16:19 UTC