Just to make sure: there are no exceptions, so every function is either total or returns a Result / Task ?
Correct
Great.
And... is there some syntax sugar for pipelines to forward to another argument than the first one? Like with a _
placeholder or similar?
caveat: Roc can panic. This happens for example when overflowing an integer type during addition. There is no way to catch/recover from this in Roc. It directly calls a platform function that decides how to proceed.
is there some syntax sugar for pipelines to forward to another argument than the first one?
No, you have to use a lambda |> \arg3 -> SomeFunc arg1 arg2 arg3
Brendan Hansknecht said:
caveat: Roc can panic. This happens for example when overflowing an integer type during addition. There is no way to catch/recover from this in Roc. It directly calls a platform function that decides how to proceed.
That's a pretty big caveat.
So essentially the +
etc operators are useless in most code, since you'd want to use addChecked
or addWrap
in most places.
well, if you are reasonably confident that +
will not overflow, it could be a reasonable operator!
Sure, but possibility for an abort in pretty much all code is not exactly why I'd use a functional language.
Wouldn't a tradeoff like Rust does it be more sensible?
Panic in debug mode, but wrap in release mode?
I thought about this, but after asking around, it seems like the worst nightmare stories around consequences of silently wrapping instead of aborting end up happening in unforeseen production edge cases that didn't come up in development
so it seems like the most reasonable designs to me are:
+
always panics on integer overflow, like it does in Roc, Zig, and others+
silently upgrades to a bigger integer type on overflow, e.g. what Python does. I don't think the perf cost of this design is acceptable in Roc's case.+
always wraps, like in CI think what Rust and C++ do gives a false sense of security, and is more error prone than any of the 3 above designs
I can get behind that reasoning, but honestly, in that case I'd be tempted to just not have the standard operators at all.
Which admittedly makes code much more awkward and unapproachable...
yeah that would be a tough sell :big_smile:
I figured this is the best default, and then in the rare cases where the performance is sensitive to arithmetic instructions being wrapped in a conditional, you can opt into Num.addWrap
and the like
What makes it really problematic is that with no exception mechanism, there probably isn't any way to recover from an overflow?
I think it is important to remember that in most code, wrapping is not the wanted functionality and would be a bug. The question is whether you want to continue executing when something would almost certainly be a bug. In systems that need to be correct, I would definitely have to go with a resounding no. If you continue executing you may end up doing something very incorrect. It is better to panic, let the platform cleanup (for example by returning a 500 if this is a web server), and then continue on.
Num.addChecked
is a way to recover
basically +
is saying "I don't expect this to overflow, but I wouldn't bet my life on it"
Yeah, so essentially you have to either ban +-*/ from your code, or assume that your program can abort at any point.
I would hereby like to request a lint/compiler flag to forbid +-*/
;)
there probably isn't any way to recover from an overflow?
The platform will be able to recover. The app will not be.
whereas Num.addWrap
is more like "I am absolutely certain this will not overflow" (or maybe you just want it to do wrapping overflow, e.g. in a hashing algorithm)
computer programs in general can abort at any point
e.g. due to stack overflows
memory is finite
if you want to absolutely guarantee that it won't happen, you have to get into things like proving there's no path through the program that could possibly exceed system resources, and run it on known hardware with multiple layers of hardware redundancy for all memory and CPU instructions, plus ample shielding from gamma rays
and that's not Roc's target audience, so we have to draw the line for fault tolerance somewhere else :big_smile:
Well, even then someone could just cut the power cable at any point. :)
I think it just hurts my sensibilities a bit.
Not even Koka
has an effect for overlow (I think).
there are other things that panic: if you concatenate lists together until the resulting list can no longer fit in memory
ps: do abilities work, or should I expect bugs?
I don't know what Koka does there, but I'm quite sure it doesn't succeed :big_smile:
so List.concat
can fail, same with string concatenation
also any language with recursive algebraic data types can have that same failure scenario, so it's not like you could even ban certain stdlib operations to rule it out - you'd have to disallow recursive sum types altogether
I'd say abilities work but have seen very minimal battle testing compared to the rest of the language, so I would definitely expect bugs just due to lack of exposure
these are great questions btw! I've thought a lot about them but haven't written them down... maybe worth a FAQ entry
If you frame it that way, pretty much every operation can fail, because in a functional language chances are it might need to allocate.
But yeah I do get you need to make a tradeoff between usability and totality.
I'd actually love an effect based language that has effects for pretty much everything that can fail (and is under the control of the language, not the OS), but allows just globally ignoring a set of effects, depending on how high-level you want your code to be.
But I probably wouldn't want to see the compile times...
The other thing zig does is give explicit wrapping operators so you choose the behaviour and then it never panics.
yeah we could always have an operator like +?
(for example) for Num.addChecked
but I'm not sure the extra benefit there is worth the cost
like Rust has add_checked
and I just use that when I want addition with overflow checking, and I haven't hoped Rust would add an operator for it...even though Rust's threshold for adding new sugar for existing functionality is massively lower than Roc's
Last updated: Jul 05 2025 at 12:14 UTC