Warnings are not a defined part of the D Programming Language. They exist at the discretion of the compiler vendor, and will most likely vary from vendor to vendor. All constructs for which an implementation may generate a warning message are legal D code.
These are the warnings generated by the Digital Mars D compiler when the -w switch is thrown. Most have generated some spirited debate as to whether it should be a warning, an error, and what the correct way to write D code in these situations should be. Since no consensus emerged, they appear as optional warnings, with alternatives on how to write correct code.
byte a,b,c; ... a = b + c;The b and c are both promoted to type int using the default integral promotion rules. The result of the add is then also int. To be assigned to a, that int gets implicitly converted to a byte.
Whether it is a bug or not in the program depends on if the values for b and c can possibly cause an overflow, and if that overflow matters or not to the algorithm. The warning can be resolved by:
a = cast(byte)(b + c);This eliminates the warning, but since casting is a blunt instrument that bypasses type checking, this can mask another bug that could be introduced if the types of a, b or c change in the future, or if their types are set by a template instantiation. (In generic code, the cast(byte) would probably be cast(typeof(a))).
byte a,b,c; int tmp; ... tmp = b + c; assert(cast(byte)tmp == tmp); a = cast(byte)tmp;This ensures that no significant bits get lost.
If length was declared as a variable name in an outer scope, that version may have been intended for use between the [ ]. For example:
char[10] a; int length = 4; ... return a[length - 1]; // returns a[9], not a[3]The warning can be resolved by:
int foo(int k, Collection c) { foreach (int x; c) { if (x == k) return x + 1; } }and assume that the nature of the algorithm is that x will always be found in c, so the foreach never falls through the bottom of the code. There is no return at the close of the function, because that point is not reachable and any return statement would be dead code. This is perfectly legitimate code. The D compiler, to help with ensuring the robustness of such code, will ensure it is correct by automatically inserting an assert(0); statement at the close of the function. Then, if there's an error in the assumption that the foreach will never fall through, it will be caught at runtime with an obvious assertion failure, which is better than the code just falling off the end causing erratic, arbitrary failures.
D's behavior on this, however, is not common to other languages, and some programmers will be acutely uncomfortable with relying on this, or they wish to see the error at compile time rather than runtime. They wish to see something explicit expressed in the source code that the foreach cannot fall through. Hence the warning.
The warning can be resolved by:
int foo(int k, Collection c) { foreach (int x; c) { if (x == k) return x + 1; } return 0; // suppress warning about no return statement }While doing this is surprisingly common, and happens when the programmer is inexperienced or in a hurry, it is a spectacularly bad solution. The trouble happens when the foreach does fall through due to a bug, then instead of the bug being detected, now the function returns an unexpected value, which may cause other problems or go undetected. There's another issue with the maintenance programmer who sees this, and upon analyzing the code's behavior, wonders why there's a return statement that will never be executed. (This can be resolved with comments, but comments are always missing, out of date, or just plain wrong.) Dead code is always a confusing problem to maintenance programming, so deliberately inserting it is a bad idea.
int foo(int k, Collection c) { foreach (int x; c) { if (x == k) return x + 1; } assert(0); }Now, if the foreach does fall through, the error will be detected. Furthermore, it is self-documenting.
int foo(int k, Collection c) { foreach (int x; c) { if (x == k) return x + 1; } throw new MyErrorClass("fell off the end of foo()"); }
switch (i) { case 1: dothis(); break; case 2: dothat(); break; }According to the D language semantics, this means the only possible values for i are 1 and 2. Any other values represent a bug in the program. To detect this bug, the compiler implements the switch as if it were written:
switch (i) { case 1: dothis(); break; case 2: dothat(); break; default: throw new SwitchError(); }This is quite different from C and C++ behavior, which is as if the switch were written:
switch (i) { case 1: dothis(); break; case 2: dothat(); break; default: break; }The potential for bugs with that is high, as it is a common error to accidentally omit a case, or to add a new value in one part of the program and overlook adding a case for it in another part. Although D will catch this error at runtime, some prefer at least a warning so such errors can be caught at compile time.
The warning can be resolved by:
switch (i) { case 1: dothis(); break; case 2: dothat(); break; default: assert(0); }
int foo(int i) { return i; return i + 1; }The second return statement is not reachable, i.e. it is dead code. While dead code is poor style in released code, it can legitimately happen a lot when rapidly trying to isolate down a bug or experiment with different bits of code. The warning can be resolved by:
int foo(int i) { return i; /+ return i + 1; +/ }
int foo(int i) { return i; version (none) { return i + 1; } }