Thread overview
Musings on infinite loops and not reachable returns
Mar 25, 2014
bearophile
Mar 25, 2014
Chris Williams
Mar 25, 2014
bearophile
Mar 25, 2014
monarch_dodra
Mar 25, 2014
anonymous
Mar 25, 2014
bearophile
March 25, 2014
This code compiles with no errors or warnings:


struct Foo {
    int opApply(int delegate(ref ubyte) dg) {
        int result;
        ubyte x;
        while (true) {
            result = dg(x);
            if (result) return result;
            x++;
        }
        //return result; // Warning: statement is not reachable
    }
}

struct Bar {
    int opApply(int delegate(ref ubyte) dg) {
        int result;
        foreach (y; Foo()) {
            result = dg(y);
            if (result) return result;
        }
        return result; // required
    }
}

void main() {}



Note how the opApply() of Foo should not end with a return, while the opApply() of Bar is required by the D compiler to end with a return.

Yet, Foo is contains an infinite loop, so the result of Bar will not be reached. But the type system of D is not strong enough to see that.

There are languages able to specify such things in their type system. But it's probably not worth adding this to the D type system (on the other hand some people have suggested to add a @noreturn annotation to D, that's usable to denote functions that never return).

Bye,
bearophile
March 25, 2014
On Tuesday, 25 March 2014 at 20:49:57 UTC, bearophile wrote:
> Note how the opApply() of Foo should not end with a return, while the opApply() of Bar is required by the D compiler to end with a return.
>
> Yet, Foo is contains an infinite loop, so the result of Bar will not be reached. But the type system of D is not strong enough to see that.

I'm not seeing it. "while (true)" is no more an infinite loop than "for (i = 0; i < x; i++)", if the body of the while has a break or return statement.

int i = 0;
while (true) {
    if (i < x) break;
    i++;
}
March 25, 2014
Chris Williams:

> I'm not seeing it. "while (true)" is no more an infinite loop than "for (i = 0; i < x; i++)", if the body of the while has a break or return statement.

I see, so there's nothing to improve here :-)

Bye,
bearophile
March 25, 2014
On Tuesday, 25 March 2014 at 20:49:57 UTC, bearophile wrote:
> This code compiles with no errors or warnings:
>
>
> struct Foo {
>     int opApply(int delegate(ref ubyte) dg) {
>         int result;
>         ubyte x;
>         while (true) {
>             result = dg(x);
>             if (result) return result;
>             x++;
>         }
>         //return result; // Warning: statement is not reachable
>     }
> }
>
> struct Bar {
>     int opApply(int delegate(ref ubyte) dg) {
>         int result;
>         foreach (y; Foo()) {
>             result = dg(y);
>             if (result) return result;
>         }
>         return result; // required
>     }
> }
>
> void main() {}
>
>
>
> Note how the opApply() of Foo should not end with a return, while the opApply() of Bar is required by the D compiler to end with a return.
>
> Yet, Foo is contains an infinite loop, so the result of Bar will not be reached. But the type system of D is not strong enough to see that.
>
> There are languages able to specify such things in their type system. But it's probably not worth adding this to the D type system (on the other hand some people have suggested to add a @noreturn annotation to D, that's usable to denote functions that never return).
>
> Bye,
> bearophile

To be honest, "statement not reachable" is a *bane* in generic code. I wish it didn't trigger in parameterized code.
Imagine this trivial case:
//----
for ( ; !r.empty ; r.popFront() )
   if (e == 5)
       return 5;
return 0;
//----

To get this to compile with all range types, including finite, infinite, and (god forbid) statically empty ranges, is a HUGE pain.

BTW:
>         return result; // required

Use "assert(0)" instead.
March 25, 2014
On Tuesday, 25 March 2014 at 20:49:57 UTC, bearophile wrote:
> This code compiles with no errors or warnings:
>
>
> struct Foo {
>     int opApply(int delegate(ref ubyte) dg) {
>         int result;
>         ubyte x;
>         while (true) {
>             result = dg(x);
>             if (result) return result;
>             x++;
>         }
>         //return result; // Warning: statement is not reachable
>     }
> }
>
> struct Bar {
>     int opApply(int delegate(ref ubyte) dg) {
>         int result;
>         foreach (y; Foo()) {
>             result = dg(y);
>             if (result) return result;
>         }
>         return result; // required
>     }
> }
>
> void main() {}
>
>
>
> Note how the opApply() of Foo should not end with a return, while the opApply() of Bar is required by the D compiler to end with a return.
>
> Yet, Foo is contains an infinite loop, so the result of Bar will not be reached. But the type system of D is not strong enough to see that.

(It's not an infinite loop, but the return is dead code.)

When you know that it won't be reached, you can (should?) put
assert(false) instead of a return.
March 25, 2014
anonymous:

> When you know that it won't be reached, you can (should?) put
> assert(false) instead of a return.

Yes, right, I use assert(false) in those cases :-)

Bye,
bearophile