<p>Many languages prioritize runtime safety by forcing users to handle (or annotate) the error cases for operations that can fail.</p>
<p>This works well for I/O and complex algorithms, but how should <em>common</em> fallible operations, like division and array access, be handled? Every <code>a / b</code> can technically fail if <code>b</code> is zero, and every <code>list[index]</code> can fail if <code>index</code> is out of range.</p>
<p>However, those operations are far too widespread to surround each instance with cumbersome error handling, or annotating with &quot;can throw division by zero&quot;.</p>
<p>How can a general-purpose programming language have this sort of operation without creating too much boilerplate for users, and without giving up safety with runtime panics?</p>
<p>Bonus points if the solution is usable for integer overflow, since it includes almost all arithmetic operations.</p>

<error-handling>
In a language with explicit error handling, how to reduce boilerplate for common fallible operations?
CC BY-SA 4.0
2023-07-01T21:10:14.763Z
Too minor to be an answer, but these operations could return an `Option` or `Result`, and your language could have some sugar for "unwrapping" those (e.g. a safe navigation operator such as `?.`, or `?` like in Rust).
user
CC BY-SA 4.0
2023-07-01T21:14:04.837Z
Even rust doesn't let you use `?` for division by zero or array indexing, they just panic
mousetail 'he-him'
CC BY-SA 4.0
2023-07-01T21:14:35.903Z
@user I think that's a perfectly ok answer, especially because Rust itself opted to not have division and array access return `Result`s. If you find out why, that's an A+ answer.
BoppreH
CC BY-SA 4.0
2023-07-01T21:23:51.213Z
@BoppreH I'd assume it's simply because it'd be too much of a pain, given how often you need to use `/` and `[]` in Rust. Rust *is* verbose, but requiring `?` for division and array access would possibly make it unbearably verbose and turn off programmers from using it. That said, I'm just guessing, I'm not even a Rust programmer. Elm returns a `Maybe` on array accesses, but that's the only mainstream language I know of that does that
user
CC BY-SA 4.0
2023-07-01T21:26:48.243Z
I’ll note that Swift, the language that was fine with adding `jo ud2` after every add and imul, said that returning an optional on array access would make it unacceptably slow.
Bbrk24
CC BY-SA 4.0
2023-07-01T21:47:47.083Z
If your language only has floats and no separate integer types, then you wouldn't need to worry about `a / 0` at all thanks to +/-Infinity and NaN.
user
<blockquote>
<p>Every <code>a / b</code> can technically fail if <code>b</code> is zero, and every <code>list[index]</code> can fail if <code>index</code> is out of range.</p>
</blockquote>
<p><code>a / b</code> can be rejected statically by a type system that ensures that the divisor is non-zero. In many cases this will be obvious, and in others it will require validation (which <em>should</em> be there anyway). Flow-sensitive typing will tend to make this more convenient, and types like &quot;non-zero integer&quot; can be propagated through parameter types so that they can be determined at the earliest possible point.</p>
<p>It is possible to <a href="https://langdev.stackexchange.com/a/1520/133">handle list indices similarly</a>, ensuring that the index is within the domain of the list. This will be still more complex, but also already necessary to ensure there isn't an error. A good dependent type checker will ensure that the validation is present when required, and not require adding more where the property has already been established. Again, parameter types can ensure this, relating a parameter used as an index to the list it corresponds to.</p>
<p>Suitable <a href="https://langdev.stackexchange.com/q/1802/133">numeric range types</a> can also prevent arithmetic overflow, although they will need to correspondingly limit what you can do: multiplication of two values needs upper bounds whose product is within the size of the container. The annotation burden of these is likely to be a bit higher than the other cases because of this.</p>
<p>It's likely that most realisations of this will reject many programs that <em>would</em> operate correctly in practice. This is a trade-off against correctness and verbosity.</p>
<hr />
<p>Another approach taken in some languages is simply to reject the idea that these <em>are</em> errors in the first place: JavaScript is perfectly happy with division by zero, it just results in Infinity, and an out-of-range index produces the <code>undefined</code> value or silently extends the array. These signal values can lead to undetected problems later on — notably, Infinity and NaN values are numbers, so even type tests don't help — and mostly move validation logic to later on at best.</p>
<p>In Perl, &quot;autovivification&quot; is an explicit language feature at a deep level: <code>$h{&quot;a&quot;}[2]{&quot;c&quot;} = 1;</code> automatically constructs the layers of intermediate hashes and arrays when non-existent indices are used. Raku inherits this approach too.</p>
<p>Similarly, cyclic treatment of list indices can make sense in some cases — we had <a href="https://langdev.stackexchange.com/q/1772/133">a question</a> recently about just that. In this case, there's no failure for any index into a non-empty list, though it may be a logic error.</p>
<hr />
<p>Calculations that can fail in the middle due to dynamic values are exactly what the option or maybe monad are for. For strings of computations where a mid-stream failure means the whole thing fails, these allow writing the code directly and having an offramp when needed.</p>
<p>A number of Haskell libraries provide division or subtraction operations of the form <code>(Num a) =&gt; a -&gt; a -&gt; Maybe a</code>: binary operations that take two numbers, and return an option type, and these work with the monadic <code>do</code> notation for easy handling:</p>
<pre class="lang-haskell prettyprint-override"><code>result = do
   a &lt;- getValue
   b &lt;- getOtherValue 2
   x &lt;- div a b
   y &lt;- normalise x
   return (y * 100)
</code></pre>
<p>At the end, <code>result</code> is either <code>Just (normalise(a / b) * 100)</code> or <code>Nothing</code>, and can be typecased to handle it at the end. If <code>normalise</code> also errored out, the result is still <code>Nothing</code>. There's no need for localised error handling for the specific division, and no non-local propagation of exceptions.</p>
<p>One realisation of this approach outside of heavily-monadic languages is sometimes called &quot;<a href="https://fsharpforfunandprofit.com/rop/" rel="nofollow noreferrer">railway-oriented programming</a>&quot;: there's a happy track, where things are working and everything just runs in sequence, and an error track where <em>any</em> problem gets redirected to. This is very like the monadic <code>do</code> above, but generally allows more handling code to run alongside starting at different points in the calculation. Sometimes it's permitted to repair and return to the successful pathway. You can find existing libraries for this in F#, Ruby, Kotlin, and other languages.</p>
<p>Option types <em>without</em> the monadic treatment are also possible, although they will generally be more cumbersome for the programmer to use. They could be worthwhile if this level of correctness is desirable, or if the language provides easy unwrapping or chaining for options (like the <code>?</code> and <code>?.</code> suffixes in some modern languages).</p>

CC BY-SA 4.0
2023-07-01T22:16:40.430Z
2023-07-01T23:28:57.730Z
2023-07-01T23:28:57.730Z
Michael Homer
# In a language with explicit error handling, how to reduce boilerplate for common fallible operations?
Posted by: username_0 on 2023-07-01
Many languages prioritize runtime safety by forcing users to handle (or annotate) the error cases for operations that can fail.

This works well for I/O and complex algorithms, but how should *common* fallible operations, like division and array access, be handled? Every `a / b` can technically fail if `b` is zero, and every `list[index]` can fail if `index` is out of range.

However, those operations are far too widespread to surround each instance with cumbersome error handling, or annotating with "can throw division by zero".

How can a general-purpose programming language have this sort of operation without creating too much boilerplate for users, and without giving up safety with runtime panics?

Bonus points if the solution is usable for integer overflow, since it includes almost all arithmetic operations.
**Tags:** error-handling
> **Comments:**
> **username_1**: Too minor to be an answer, but these operations could return an `Option` or `Result`, and your language could have some sugar for "unwrapping" those (e.g. a safe navigation operator such as `?.`, or `?` like in Rust).  
> **username_2**: Even rust doesn't let you use `?` for division by zero or array indexing, they just panic  
> **username_0**: @user I think that's a perfectly ok answer, especially because Rust itself opted to not have division and array access return `Result`s. If you find out why, that's an A+ answer.  
> **username_1**: @BoppreH I'd assume it's simply because it'd be too much of a pain, given how often you need to use `/` and `[]` in Rust. Rust *is* verbose, but requiring `?` for division and array access would possibly make it unbearably verbose and turn off programmers from using it. That said, I'm just guessing, I'm not even a Rust programmer. Elm returns a `Maybe` on array accesses, but that's the only mainstream language I know of that does that  
> **username_3**: I’ll note that Swift, the language that was fine with adding `jo ud2` after every add and imul, said that returning an optional on array access would make it unacceptably slow.  
> **username_1**: If your language only has floats and no separate integer types, then you wouldn't need to worry about `a / 0` at all thanks to +/-Infinity and NaN.  
---
## 1 answers
### Answer by username_4 on 2023-07-01. Score: 4 | Accepted answer
Every a / b can technically fail if b is zero, and every list[index] can fail if index is out of range.

a / b can be rejected statically by a type system that ensures that the divisor is non-zero. In many cases this will be obvious, and in others it will require validation (which should be there anyway). Flow-sensitive typing will tend to make this more convenient, and types like "non-zero integer" can be propagated through parameter types so that they can be determined at the earliest possible point.
It is possible to handle list indices similarly, ensuring that the index is within the domain of the list. This will be still more complex, but also already necessary to ensure there isn't an error. A good dependent type checker will ensure that the validation is present when required, and not require adding more where the property has already been established. Again, parameter types can ensure this, relating a parameter used as an index to the list it corresponds to.
Suitable numeric range types can also prevent arithmetic overflow, although they will need to correspondingly limit what you can do: multiplication of two values needs upper bounds whose product is within the size of the container. The annotation burden of these is likely to be a bit higher than the other cases because of this.
It's likely that most realisations of this will reject many programs that would operate correctly in practice. This is a trade-off against correctness and verbosity.

Another approach taken in some languages is simply to reject the idea that these are errors in the first place: JavaScript is perfectly happy with division by zero, it just results in Infinity, and an out-of-range index produces the undefined value or silently extends the array. These signal values can lead to undetected problems later on — notably, Infinity and NaN values are numbers, so even type tests don't help — and mostly move validation logic to later on at best.
In Perl, "autovivification" is an explicit language feature at a deep level: $h{"a"}[2]{"c"} = 1; automatically constructs the layers of intermediate hashes and arrays when non-existent indices are used. Raku inherits this approach too.
Similarly, cyclic treatment of list indices can make sense in some cases — we had a question recently about just that. In this case, there's no failure for any index into a non-empty list, though it may be a logic error.

Calculations that can fail in the middle due to dynamic values are exactly what the option or maybe monad are for. For strings of computations where a mid-stream failure means the whole thing fails, these allow writing the code directly and having an offramp when needed.
A number of Haskell libraries provide division or subtraction operations of the form (Num a) => a -> a -> Maybe a: binary operations that take two numbers, and return an option type, and these work with the monadic do notation for easy handling:
result = do
   a <- getValue
   b <- getOtherValue 2
   x <- div a b
   y <- normalise x
   return (y * 100)

At the end, result is either Just (normalise(a / b) * 100) or Nothing, and can be typecased to handle it at the end. If normalise also errored out, the result is still Nothing. There's no need for localised error handling for the specific division, and no non-local propagation of exceptions.
One realisation of this approach outside of heavily-monadic languages is sometimes called "railway-oriented programming": there's a happy track, where things are working and everything just runs in sequence, and an error track where any problem gets redirected to. This is very like the monadic do above, but generally allows more handling code to run alongside starting at different points in the calculation. Sometimes it's permitted to repair and return to the successful pathway. You can find existing libraries for this in F#, Ruby, Kotlin, and other languages.
Option types without the monadic treatment are also possible, although they will generally be more cumbersome for the programmer to use. They could be worthwhile if this level of correctness is desirable, or if the language provides easy unwrapping or chaining for options (like the ? and ?. suffixes in some modern languages).
---
