I was reading a blog entry about zero defect code and saw the following horrible Ada code (with a strange mix of constants, hard-coded values, and what resembles an off-by-one error):
subtype LogFileIndexT is LogFileCountT range 1 .. MaxNumberLogFiles; subtype FileNameI is Positive range 1 .. 16; subtype FileNameT is String(FileNameI); type LogFileNamesT is array (LogFileIndexT) of FileNameT; LogFileNames : constant LogFileNamesT := LogFileNamesT'( 1 => "./Log/File01.log", 2 => "./Log/File02.log", 3 => "./Log/File03.log", 4 => "./Log/File04.log", 5 => "./Log/File05.log", 6 => "./Log/File06.log", 7 => "./Log/File07.log", 8 => "./Log/File08.log", 9 => "./Log/File09.log", 10 => "./Log/File10.log", 11 => "./Log/File11.log", 12 => "./Log/File12.log", 13 => "./Log/File13.log", 14 => "./Log/File14.log", 15 => "./Log/File15.log", 16 => "./Log/File16.log", 17 => "./Log/File17.log" );
Now I suppose, under the hood, that this might offer some sort of static benefit (memory allocation?), but here's that code in Perl 6 (as best as I can tell):
sub logFileName ( Int $n where { 0 < $_ <= 17 } ) { return sprintf "./Log/File%02d.log", $n; } say logFileName($_) for 1 .. 17;
We get a runtime exception instead of a compile time exception if the argument is out of bounds, but it seems pretty clear. The author, however, tried to translate it to Java and failed to preserve functionality:
static String logFileName(int n) { Formatter f = new Formatter(); return f.format("./Log/File%02d.log", n).toString(); }
Yup. We're going to love Perl 6.
Note that you can also write the Perl 6 code as:
sub logFileName ( Int $n where { $^N > 0 and $^N <= 17 } ) { return "./Log/File%02d.log".sprinf($n); } say logFileName($_) for 1 .. 17;
TIMTOWTDI still rules.
I think it should be kept in mind that the purpose of this code is that is should be correct according to specification in a safety critical system. As such correctness is more important than the code being easy to maintain etc. Using static code makes more compiler checks possible and correct proofs easier, but in this case the code probably got uglier (but I don't know any Ada so it is hard to say for me)
For better explanations see the comments to the original article.
Re:Static code not always bad
Ovid on 2008-10-19T15:08:03
Many of the comments were interesting and I assume that my ignorance of Ada and the requirements are the reason why I am not understanding why this code is good. I would be surprised to hear that the NSA is touting bad code as good code, but then, I really don't know enough about them (who does?) to say. If the US Military had put this out instead of the NSA, I'd be far more likely to believe that it's bad.
As for the Perl 6 code, I do think that the function is amenable to static compile-time analysis, but the ability to mutate the language at runtime removes much of the benefit there.
To start with, Ada indexes arrays starting with 1. Yes, I know that is ugly and weird (*cough* FORTRAN *cough*), but that is most certainly not an off-by-one error.
Next, neither your p6 code or the java code addresses the line:
subtype LogFileIndexT is LogFileCountT range 1
.. MaxNumberLogFiles;
Granted there are some missing values here, specifically LogFileCountT and MaxNumberLogFiles. But these two help to define a range of acceptable indices for the LogFileNamesT array type.
Now to the really bad assumptions, the following two lines:
subtype FileNameI is Positive range 1
.. 16;
subtype FileNameT is String(FileNameI);
were completely misinterpreted by the blogger, this is not saying "only allow 16 log files in my array", it is saying that the file names are only allowed to be a string of 16 characters long. The actual number of allowed log files in the array is determined by MaxNumberLogFiles, which I suspect has to be less then 100 since otherwise the strings would be too long.
Now, as for the question of why so static? Probably because this code is meant to run in an embedded system which has very limited resources so the more specific the programmer can be about the size and shape of the memory they want to use (an array MaxNumberLogFiles long made up of 16 char strings) the more efficient the compiler can be about allocating that storage.
As for why they hardcoded the first 17 log file names, I am suspecting this is because this code was also written for what I called a hard real-time system, which means it must, and I mean MUST perform a task within a given time frame and failure to do so could likely endanger peoples lives. By hardcoding the first 17 files they are probably saving precious CPU cycles (17 must be some kind of magic number, a sweet spot if you will) and (as one of the commenters pointed out) possibly helping some kind of formal proofing tool.
Lastly, the fact we would (in p6) get a runtime exception would in no way shape or form be acceptable for a safety critical system. Would you really want to have the pilot of the plane you are flying have to deal with a stack trace from some kind of runtime exception? Or the safety inspector (Homer Simpson anyone) at the nuclear power plant to have to figure out what just blew up in the code before the core melts down and actually blows up?
Ada is not pretty, it is not friendly, it is not agile, it is not clever. It is tedious, ugly, draconian and safe.
- Stevan
Re:Assumptions are bad
Aristotle on 2008-10-19T16:36:59
And what people miss is that while this sort of safety is a must when lives are on the line, it is prohibitively costly to achieve in, say, one-liners.
But programmers like to view the world in black&white.
Hey Look, Withering Irony!
chromatic on 2008-10-20T17:51:31
But programmers like to view the world in black&white.
Are you saying non-programmers don't?
Re:Hey Look, Withering Irony!
Ovid on 2008-10-20T18:06:44
Heh. I found myself wishing I could upvote this.
Re:Hey Look, Withering Irony!
Aristotle on 2008-10-20T18:19:53
What I am saying is some disciplines seem to invite dogmatism and simplisticism more than others.
Comment thread discussions, f.ex.…
Re:Assumptions are bad
Ovid on 2008-10-20T14:41:00
Stevan, thanks for all of the background information here. It's nice to get a different perspective on things.
Re:Assumptions are bad
rurban on 2008-10-21T08:18:29
16 is the magic number, even in ADA there is 2-complement HW.
index 1-17, count=16I also deal with security relevant hard real-time code. We mostly use graphical environments there, Matlab Simulink, the deal with the additional complexity.
There the checks are mostly runtime, not compile time! "Compile time" checks are done by the graphical environment, where boxes simply cannot be connected, or invalid parameters cannot be entered.