I had a professor for two semesters that required that all our assignments were written in C. This was his assignment submission policy:
1) Run lint on all your code.
2) All code must have zero warnings from lint, with no exceptions.
3) Any use of
strcpyresulted in a zero for the assignment.
#3 was my first lesson about buffer overflows. (We all used
One of the lint warnings pertained to unused return values. For instance, the method signature for
How often is
int printf(char *format,...)
printf's returned value given attention? It represents the number of characters written to the stream, or a negative number on failure.
Our linter complained about unused return values for typical uses of
We were required to either accept and process the return value, or explicitly disregard it:
This was one of my earliest impressions of studying defensive programming.
In Java, the method
java.io.InputStream.skiphas a contract that requires you to pay attention to the return value, and the reason may surprise you:
So, you supply a distance to skip, and you likely expect the same value back, at least, most of the time. What amazes me is that the documentation even addresses the common expectation: sure EOF is one waypublic long skip(long) throws IOExceptionThe
skipmethod may, for a variety of reasons, end up skipping over some smaller number of bytes, possibly
This may result from any of a number of conditions; reaching end of file before
bytes have been skipped is only one possibility. The actual number of bytes skipped is returned. If
nis negative, no bytes are skipped.
skip(n) != n, and then says, twice, that there may be a "variety of reasons" and a "number of conditions." The author is trying to make up for a troublesome API with special javadoc.
Forget that oftentimes there's no documentation and hence, no contract, you still can't expect that documenting unexpected behavior is going to result in proper use of the API.
Present day, Java has Findbugs, The Lint Of Java (zero results, you saw it here first!) Java's classfile format and FindBugs' semantic analysis makes it much more powerful than lint, it can identify this issue with
java.io.InputStream.skip(). From the description as Findbugs reports it:
This method ignores the return value ofThat's great, but there's a problem, and that comes with expanding the API. If I build my own API with its own nuances, someone needs to write a FindBugs detector. (Hint: be careful writing a clever API!)
java.io.InputStream.skip()which can skip multiple bytes. If the return value is not checked, the caller will not be able to correctly handle the case where fewer bytes were skipped than the caller requested. This is a particularly insidious kind of bug, because in many programs, skips from input streams usually do skip the full amount of data requested, causing the program to fail only sporadically. With Buffered streams, however, skip() will only skip data in the buffer, and will routinely fail to skip the requested number of bytes.
It seems draconian to enforce a policy of "always address return values" with Java outside academia since there's no easy way to mimic the explicit cast to
void. Otherwise you wind up with unused local variables, which becomes yet another code smell.
In the end all tools like FindBugs and lint only augment the human analysis that accompanies development.
I hope students today are being told that they cannot turn in any Java assignments without running FindBugs.