Direct recursion detection possible?
Quirin Schroll
qs.il.paperinik at gmail.com
Thu May 25 16:44:10 UTC 2023
On Thursday, 25 May 2023 at 15:51:15 UTC, Ali Çehreli wrote:
> On 5/24/23 16:04, Cecil Ward wrote:
>
> > Is it possible for our compilers to detect direct infinite
> recursion?
>
> I agree the compiler can detect some cases. However, a
> diagnostic may not be what the programmer wants in all cases.
>
> I am writing on this topic because I've recently been
> pleasantly surprised how dmd lets me inject assert(false)
> expressions during development:
> ```d
> void foo() {
> someCode();
>
> assert(false, "some information");
>
> moreCode();
> }
> ```
> I am a `printf`-style programmer, where I use such asserts as
> well.
>
> I *think* the compiler used to complain about that in earlier
> versions (or maybe I remember compilers of earlier languages
> like C++?); the compiler would say "unreachable code".
>
> I am thankful that dmd allows me do it during development and
> debugging.
>
> So, your case may fall into this category where although it
> doesn't make sense, a programmer may have caused it
> intentionally.
I just tried what DMD does with
```d
for (ubyte i = 0; i < 256u; ++i) { ... }
```
It doesn’t care that `i < 256` is trivially true (by type). GCC
and Clang give me:
```
warning: comparison is always true due to limited range of data
type (GCC)
warning: result of comparison of constant 256 with expression of
type 'unsigned char' is always true (Clang)
```
(For the record, in C++, this is platform dependent; there’s no
guarantee by the language that `unsigned char` is only 8-bit.)
An `assert(false)` leading to dead code is indeed similar, but
also different from an infinite loop/recursion. This is
opinionated: `assert(false)` is placed with intention; it’s a
good question if (or under which circumstances) dead code should
be an error; dead code is dubious and in a release build or
otherwise optimized build, in non-template code, I’d probably
like the compiler telling me about it. An infinite loop/recursion
without observable effects is almost certainly not intentional
and something is wrong: The condition is wrong or the body
doesn’t affect the condition as intended. Even in a debug build,
it would be valuable to have the info. There could be 3 degrees
of diagnostic:
1. In a debug build, an infinite loop/recursion, if detected,
produces a warning. One big reason for this is that in debug
mode, `pure` functions can actually have observable effects.
2. In a regular (non-debug, non-release, non-optimized) build, an
infinite loop/recursion by syntax (something like `while(1){}` or
`int f(int x) => f(x)` and a little less basic examples) are
errors (because they’re obviously wrong and should be detected by
any compiler) and infinite loop/recursion by (deep) semantic
analysis gets a warning.
3. In optimized/release, any detected infinite loop/recursion is
an error.
Of course, by infinite loop/recursion, I mean those without
observable effects, but “infinite loop/recursion” is wordy
enough. A read–eval–print loop is perfectly fine. I might add
that `pure` is not enough. Throwing an exception can break a
loop, so `nothrow` is required as well for all the operations in
question.
More information about the Digitalmars-d
mailing list