<p>Several languages have a function or macro to indicate that a certain point in control flow cannot be reached, even though the compiler cannot statically prove it, such as <a href="https://doc.rust-lang.org/std/macro.unreachable.html" rel="nofollow noreferrer"><code>unreachable!()</code></a> in Rust and <a href="https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005funreachable" rel="nofollow noreferrer"><code>__builtin_unreachable()</code></a> in gcc.</p>
<p>However, some languages don't have this. Even Swift, which borrowed many features from Rust, omits this -- you have to call <code>fatalError</code> (equivalent to <code>panic!</code>) instead. <strong>In languages with static analysis that make this relevant</strong>, why would it be beneficial to omit this function?</p>

<control-flow><never-type><static-analysis>
Why do some languages not have an 'unreachable' function?
CC BY-SA 4.0
2023-05-18T03:10:20.793Z
Didn't you mean to compare `__builtin_unreachable` with Rust's [`unreachable_unchecked`](https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html)? Rust's `unreachable!` is not equivalent to GCC's since the former panics in a defined way, while the later will lead to UB if the code path reaches it.
Luiz Felipe
CC BY-SA 4.0
2023-05-18T03:17:34.710Z
Rust's `uncreachable` is equivalent to `panic`, as the docs say.
kaya3
CC BY-SA 4.0
2023-05-18T03:25:08.287Z
@LuizFelipe I honestly prefer a checked function -- see [my `unreachable` macro here](https://github.com/bbrk24/Trilangle/blob/master/compat.hh#L146), for example -- it's just that I don't know of any builtin like this in C/C++.
Bbrk24
CC BY-SA 4.0
2023-05-18T03:29:44.377Z
Yeah, I see. I'm not sure if Rust's `unreachable_unchecked` panics in a well-defined manner in debug builds. As per the docs, I think it doesn't. However, `unreachable!` is always checked—both in debug and release builds.
Luiz Felipe
<p><a href="https://mercurylang.org/" rel="nofollow noreferrer">Mercury</a> has a different solution. Being a logic language, it has a notion of a predicate/procedure returning multiple solutions (via backtracking) and failing. But it also has a <a href="https://mercurylang.org/information/doc-release/mercury_ref/Determinism-categories.html" rel="nofollow noreferrer">strong determinism system</a>, which means that the degree of determinism or nondeterminism of a particular mode of a predicate is known at compile time.</p>
<p>So, for example, a mode of a predicate which has one solution and cannot fail is <em>deterministic</em>, which is called <code>det</code> in Mercury. A mode which has one solution but can fail is called <em>semideterministic</em>; this, for example, is the type of a test predicate. The case of many solutions is also split into two: <em>nondeterministic</em> if it can fail, and <em>multideterministic</em> if it cannot.</p>
<p>The interesting cases for the purpose of this question is when a procedure can have zero solutions:</p>
<pre><code>                Maximum number of solutions
Can fail?       0               1               &gt; 1
no              erroneous       det             multi
yes             failure         semidet         nondet
</code></pre>
<p>Despite the names <code>failure</code> and <code>erroneous</code>, these are not incorrect determinism categories. The <code>failure</code> category is the determinism of <code>fail</code>, the goal that always fails. And <code>erroneous</code> is the determinism of a fatal error (called <code>error/1</code> in Mercury) or raising an exception.</p>
<p>This is an important part of the semantics of the language. It means that you can write code like this:</p>
<pre><code>sqrt(X) = SquareRoot :-
    ( if math_domain_checks, X &lt; 0.0 then
        throw(domain_error(&quot;math.sqrt&quot;))
    else
        SquareRoot = unchecked_sqrt(X)
    ).
</code></pre>
<p>If the call to <code>throw/1</code> were not declared as <code>erroneous</code>, this would be a compile error. Both branches of the if-then-else must bind a value to the variable <code>SquareRoot</code> for it to be available to return from this function. But it is not an error here because the compiler knows that the <code>then</code> path is a dead-end, so it never has to supply a value.</p>

CC BY-SA 4.0
2023-05-18T05:33:03.667Z
2023-05-18T05:33:03.667Z
Pseudonym
<h1>It's not necessary</h1>
<blockquote>
<p>you have to call fatalError (equivalent to panic!) instead</p>
</blockquote>
<p>What's the problem? Doesn't this work just fine?</p>
<p>Also, many languages aren't strict enough to require this - they don't care if your code is reached or not.</p>

CC BY-SA 4.0
2023-05-18T03:12:30.047Z
2023-05-18T03:12:30.047Z
naffetS
CC BY-SA 4.0
2023-05-18T05:00:33.810Z
Without some kind of feedback, it's not clear to the compiler that `fatalError` or `panic` never returns. This may introduce warnings or even errors in some languages; consider a variable which is initialised along all reachable code paths but uninitialised along unreachable ones. The programmer ideally should not get a warning/error about an uninitialised variable in this case.
Pseudonym
CC BY-SA 4.0
2023-05-18T21:41:03.953Z
@Pseudonym I think it should be clear, many languages have it as an actual keyword (`throw`/`raise`), so it's not just a regular macro, it's something the compiler should recognize.
naffetS
<p>As you pointed out, these markers are useful when the compiler <em>can't</em> statically prove that the code path is unreachable. You, as the programmer, <em>may</em> use them when you are <em>sure</em> that such a code path is indeed—and <em>certainly</em>—unreachable. Otherwise, here be dragons!</p>
<p>Both GCC's <code>__builtin_unreachable</code> and Rust's <code>unreachable_unchecked</code> serve as an <em>unsafe</em> optimization that you, the programmer, used to <em>eliminate</em> some code path that will never be executed.</p>
<blockquote>
<p>Why do some languages not have an 'unreachable' function?</p>
</blockquote>
<p>These other languages probably shouldn't allow such kind of <em>unsafety</em>.</p>
<p>See, the compiler will erase all code paths that led to the unreachable marker, which can cause UB if the code path is reached.</p>
<p>Programmers can make wrong assumptions, so most languages can't afford to allow unchecked unsafe operations, even at the cost of optimization.</p>
<p>In the case of C and C++, the language is, by definition, &quot;unsafe&quot;, and the programmer is responsible for ensuring the program's safety; hence, the annotation is available.</p>
<p>In Rust, <code>unreachable_unchecked</code> must be put behind an <code>unsafe</code> block, leaving the programmer responsible for the program's safety.</p>
<p>Rust's <code>unreachable!</code> macro is safe because it will <em>panic</em> (in a defined manner) if the code reaches it. Unlike <code>unreachable_unchecked</code>, the <code>unreachable!</code> macro won't trigger any optimizations by itself; it is just commonly used as a more <em>semantically</em> appropriate way of panicking.</p>

CC BY-SA 4.0
2023-05-18T03:18:04.020Z
2023-05-18T03:27:59.880Z
2023-05-18T03:27:59.880Z
Luiz Felipe
# Why do some languages not have an 'unreachable' function?
Posted by: username_0 on 2023-05-18
Several languages have a function or macro to indicate that a certain point in control flow cannot be reached, even though the compiler cannot statically prove it, such as [`unreachable!()`](https://doc.rust-lang.org/std/macro.unreachable.html) in Rust and [`__builtin_unreachable()`](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005funreachable) in gcc.

However, some languages don't have this. Even Swift, which borrowed many features from Rust, omits this -- you have to call `fatalError` (equivalent to `panic!`) instead. **In languages with static analysis that make this relevant**, why would it be beneficial to omit this function?
**Tags:** control-flow never-type static-analysis
> **Comments:**
> **username_1**: Didn't you mean to compare `__builtin_unreachable` with Rust's [`unreachable_unchecked`](https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html)? Rust's `unreachable!` is not equivalent to GCC's since the former panics in a defined way, while the later will lead to UB if the code path reaches it.  
> **username_2**: Rust's `uncreachable` is equivalent to `panic`, as the docs say.  
> **username_0**: @LuizFelipe I honestly prefer a checked function -- see [my `unreachable` macro here](https://github.com/bbrk24/Trilangle/blob/master/compat.hh#L146), for example -- it's just that I don't know of any builtin like this in C/C++.  
> **username_1**: Yeah, I see. I'm not sure if Rust's `unreachable_unchecked` panics in a well-defined manner in debug builds. As per the docs, I think it doesn't. However, `unreachable!` is always checked—both in debug and release builds.  
---
## 3 answers
### Answer by username_1 on 2023-05-18. Score: 9 | Accepted answer
As you pointed out, these markers are useful when the compiler *can't* statically prove that the code path is unreachable. You, as the programmer, *may* use them when you are *sure* that such a code path is indeed—and *certainly*—unreachable. Otherwise, here be dragons!

Both GCC's `__builtin_unreachable` and Rust's `unreachable_unchecked` serve as an *unsafe* optimization that you, the programmer, used to *eliminate* some code path that will never be executed.

> Why do some languages not have an 'unreachable' function?

These other languages probably shouldn't allow such kind of *unsafety*.

See, the compiler will erase all code paths that led to the unreachable marker, which can cause UB if the code path is reached.

Programmers can make wrong assumptions, so most languages can't afford to allow unchecked unsafe operations, even at the cost of optimization.

In the case of C and C++, the language is, by definition, "unsafe", and the programmer is responsible for ensuring the program's safety; hence, the annotation is available.

In Rust, `unreachable_unchecked` must be put behind an `unsafe` block, leaving the programmer responsible for the program's safety.

Rust's `unreachable!` macro is safe because it will *panic* (in a defined manner) if the code reaches it. Unlike `unreachable_unchecked`, the `unreachable!` macro won't trigger any optimizations by itself; it is just commonly used as a more *semantically* appropriate way of panicking.
---
### Answer by username_4 on 2023-05-18. Score: 3
# It's not necessary

> you have to call fatalError (equivalent to panic!) instead

What's the problem? Doesn't this work just fine?

Also, many languages aren't strict enough to require this - they don't care if your code is reached or not.
> **Comments:**
> **username_3** (2023-05-18): Without some kind of feedback, it's not clear to the compiler that `fatalError` or `panic` never returns. This may introduce warnings or even errors in some languages; consider a variable which is initialised along all reachable code paths but uninitialised along unreachable ones. The programmer ideally should not get a warning/error about an uninitialised variable in this case.  
> **username_4** (2023-05-18): @Pseudonym I think it should be clear, many languages have it as an actual keyword (`throw`/`raise`), so it's not just a regular macro, it's something the compiler should recognize.  
---
### Answer by username_3 on 2023-05-18. Score: 2
Mercury has a different solution. Being a logic language, it has a notion of a predicate/procedure returning multiple solutions (via backtracking) and failing. But it also has a strong determinism system, which means that the degree of determinism or nondeterminism of a particular mode of a predicate is known at compile time.
So, for example, a mode of a predicate which has one solution and cannot fail is deterministic, which is called det in Mercury. A mode which has one solution but can fail is called semideterministic; this, for example, is the type of a test predicate. The case of many solutions is also split into two: nondeterministic if it can fail, and multideterministic if it cannot.
The interesting cases for the purpose of this question is when a procedure can have zero solutions:
                Maximum number of solutions
Can fail?       0               1               > 1
no              erroneous       det             multi
yes             failure         semidet         nondet

Despite the names failure and erroneous, these are not incorrect determinism categories. The failure category is the determinism of fail, the goal that always fails. And erroneous is the determinism of a fatal error (called error/1 in Mercury) or raising an exception.
This is an important part of the semantics of the language. It means that you can write code like this:
sqrt(X) = SquareRoot :-
    ( if math_domain_checks, X < 0.0 then
        throw(domain_error("math.sqrt"))
    else
        SquareRoot = unchecked_sqrt(X)
    ).

If the call to throw/1 were not declared as erroneous, this would be a compile error. Both branches of the if-then-else must bind a value to the variable SquareRoot for it to be available to return from this function. But it is not an error here because the compiler knows that the then path is a dead-end, so it never has to supply a value.
---
