[Home]
[Search]
[D]
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;
}
}