# What are examples of inconsistency and incompleteness in Unix/C?

In Richard Gabriel's famous essay The Rise of Worse is Better, he contrasts caricatured versions of the MIT/Stanford (Lisp) and New Jersey (C/Unix) design philosophies along the axes of simplicity, correctness, consistency, and completeness. He gives the example of the "PC loser-ing problem" (discussed elsewhere by Josh Haberman) to argue that Unix prioritizes simplicity of implementation over simplicity of interface.

One other example I've come up with is the different approaches to numbers. Lisp can represent arbitrarily large numbers (up to the size of memory), while C limits numbers to a fixed number of bits (typically 32-64). I think this illustrates the correctness axis.

What are some examples for consistency and completeness? Here are all of Gabriel's descriptions (which he admits are caricatures):

The MIT/Stanford approach

• Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.
• Correctness -- the design must be correct in all observable aspects. Incorrectness is simply not allowed.
• Consistency -- the design must not be inconsistent. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.
• Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.

The New Jersey Approach

• Simplicity -- the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.
• Correctness -- the design must be correct in all observable aspects. It is slightly better to be simple than correct.
• Consistency -- the design must not be overly inconsistent. Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.
• Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.

Please note I am not asking whether Gabriel is right (which is a question not appropriate for StackExchange) but for examples of what he might have been referring to.

-
In case you're curious, this isn't a homework problem. I'm the teacher. :-) On second thought, maybe that makes it my homework. – espertus Apr 15 '12 at 0:24
I struggle to see why this question is not on Unix & Linux (or maybe Programmers?). Can you elaborate on in which way you need a CS perspective on the matter? Also, please clarify whether you want positive or negative examples. – Raphael Jan 14 '13 at 22:34

The question's title suggests that some basic user interface inconsistencies may interest you:

Unix commands don't follow any particular syntax for specifying options and flags. For example, most commands use single letters preceded by '-' as flag: cat -n some_file, but exceptions like tar tf some_file.tar and dd in=some_file out=some_other_file count=2 exist in commonly used commands.

Unix and its descendants and relatives have multiple slightly different regular expression syntaxes. Shells use "*" where other programs (grep, egrep, vi) use '.*'. egrep has '+' and '|' as operators, grep does not.

The basic "everything is a file" system call interface could be viewed as incomplete: read/write/seek/close doesn't fit every I/O device. Badly needed exceptions get lumped into "ioctl" calls, but devices like sound cards don't even fit that very well.

-
Nice answer. When I saw the title I was immediately thinking "ioctl" (and fcntl) but now I don't have to type an answer. – Louis Apr 20 '12 at 7:51
glob patterns are not regexs – jk. Jan 23 '13 at 15:10

Consistency

Lisp has a very consistent syntax, all language extensions can be embedded naturally via macros and such. C, on the other hand, has a rather code syntax, which allows one to take some "shortcuts", so in some cases C code actually look simplier.

Completeness

In Lisp, if you do not have a specific language feature you need, you can implement it yourself with macros. C too has preprocessor, but it is rather perplexing.

-

C's strings cannot contain character 0 and its library functions are unsuitable for dealing with binary data.

Filenames on Unix systems cannot contain character 0 or character 47 (the slash).

In the original implementation of Unix, filenames were limited to 14 characters. Later versions only relaxed this limitation; they did not eliminate it.

Added: The E2BIG system error condition, when one tried to exec with an argument list that had too many arguments, or occupied too much memory, or an environment that was too big.

Unix is notorious for this sort of arbitrary limitation. Until the advent of Perl in 1987, handling large data sets, or data sets with long records, or binary data, was extremely unreliable.

-
Not allowing / is not arbitrary, it is necessary (?) to resolve ambiguities as / is the path separator. I just created a file 000, apparently that specific restriction is gone in the days of a modern GNU/Linux. – Raphael Jan 21 '13 at 11:02
I did not mean to say that the prohibition of / was arbitrary, only that line length and file size limits were arbitrary.The point, however, is that a different design could have allowed filenames to contain slashes, but the designers of Unix didn't consider it important. – Mark Dominus Jan 21 '13 at 22:04
I am sure that at the time, those limits were introduced due to performance considerations; undeveloped techniques may play into it, too. From today's point of view, they seem questionable, that's for sure. Regarding /, I am curious: assuming a path should be encoded as string, how do you do that without a reserved character for path separation? – Raphael Jan 21 '13 at 23:09
I don't understand what your point is. The question asks for "examples of inconsistency and incompleteness in Unix/C"; it does not mention performance. – Mark Dominus Jan 22 '13 at 0:25
If you actually need a reserved character for path separation, it is not an inconsistency but a necessity. Since you claim it is an inconsistency (if anything, it rather is a shortcoming, but let's not discuss that) I am honestly interested how you would do away with it. – Raphael Jan 22 '13 at 19:24

IIRC my teacher said the inability to use char * variables in switch statements in C is a matter of inconsistency, but for me that was generality (completeness) issue. I think it's better to use "consistency" just in your algorithms or software design not in programming language itself (at least not in languages like C. maybe a buggy language has consistency issue), because programming languages have solid standards that define domain of rules and work by applying input to rules. So if something is not allowed in language, it planned to not being allowed and is not inconsistency in language, IMHO.

1. I've used generality as completeness. i think they are same thing. maybe I'm wrong.
2. This is Not an answer. maybe suggestion or my opinion.
-
• Certainly the myriad meanings of the same (short) flags to commands is an inconsistency.
• Each program that uses regular expressions has it's own syntax for them
• Configuration files for services are all different syntax (that can be forgiven in part, your mailer daemon has little in common with your webserver or system startup, but still)
• There are different editors! Users use different shells!! Why are there so many desktop environments?!?

OTOH, the fact that the shell expands globs, and not the progam, eliminates a lot of irritating inconsistencies present in other systems. Ditto the fact that you can use the same command to copy a file from one place to the other in the filessytem, to a diskette or from a Zip disk to tape.

So, yes, Unix is inconsistent. So are the other systems, just differently ;-)

-

The best example I have is the poor user who had a file named .. -r and typed in rm *.

Whether this story is true or not, it's become a Unix hater's classic.

See The Unix-Haters Handbook, which has an introduction by Dennis Ritchie himself, for lots of these examples.

I'll add furthermore that avoiding these types of problems was a major force in the design of Microsoft's Power Shell.

-
I read Richard Gabriel's essay in the back of The Unix-Haters Handbook. :-) – espertus Jan 16 '13 at 4:42