News for hackers. Stuff that matters.
Re:The Problem with Friendly C by derefr on Thursday December 24, 2015 @09:36PM (#10790232)
I agree with pretty much everything you wrote here. I think my main disagreement is that you can fix this at the language level. Languages are static entities; some are "living" in the sense that they get new major revisions (C++0x, Python 3, etc.) but on a day-to-day basis, you have to deal with the language you've got, and most languages don't have any way to "annotate in" these sort of semantics on a per-module basis. (C is one of the only places this has been given even bare thought, actually, with compiler #pragmas.)

IMHO the goal of a compiler is this: to take as input 1. code represented in some standard grammar, and 2. configuration represented in a compiler-specific format; and to combine these two things to generate a build artifact.

I assume that you want the build artifact to have the same deterministic behavioral semantics on all target platforms, regardless of whether your language allows you to encode those semantics. Insofar as compilers have the two inputs stated above, then each semantic property that can't be made explicit by the language grammar, must then fall to the compiler's configuration.

In other words, it's the compiler's job (through you) to fix the language's mistakes, such that vague code becomes non-vague binaries.

Imagine for a moment that, instead of global command-line switches passed directly to the compiler, the compiler's configuration existed in the form of a "hints file" alongside each source file—effectively, a proprietary system of markup/annotations for the language, but separated into its own file instead of being intermingled in the source like Java's @annotations.

In such a model, you'd have a 1:1 correspondence between input #1 and input #2: each file of C code would have an equivalent file of hints, telling the compiler everything it needs to know that isn't in the C code (and which, moreover, can't actually be expressed at all in C.)

With our current backwards batch-programming methodologies, you'd probably have to write the "hint" files yourself, or have your IDE generate them by twiddling knobs. My real expectation, though, is that your compiler would actually run through your source files interactively, asking you questions where it thinks things are vague and recording the answers in its hint files, only actually doing a compilation pass once all its questions have been answered. Your compiler would actually work with you like a copy-editor, taking your muddled prose and putting in little query-marks to show its confusion.

Which is all to say, we're never going to get a revision of the C language standard that will actually give "x + y" platform-independent overflow semantics. But we could definitely create compilers that would annotate each "x + y" in a C codebase with a particular overflow semantics, without doing anything to the code itself that breaks the C language grammar. This would let us remove the vast majority of what is currently "undefined behavior" from our code, without fighting a losing battle for more semantically-explicit languages.

Re:The Problem with Friendly C by zAy0LfpBZLC8mAC on Thursday December 24, 2015 @10:10PM (#10790285)
> Anyway, that's all to say, IMHO the goal of a compiler is to take as input 1. code represented in some standard grammar, and 2. configuration represented in a compiler-specific format, and combine these to generate a build artifact.

Then, what you really are doing is defining a new language. And one with a horrible syntax at that. If the "code" alone does not actually describe what the program is supposed to do, that "configuration" becomes part of the program (if the binary's behaviour changes depending on whether you compile it with or without the "configuration", it is obviously part of the code), and having parts of your program kindof "out of band" is about the worst idea ever for auditing and maintenance, and for general readability. Also, given that that part of your new language is not part of the C standard, say, you cannot use any C compiler to compile it. If you are lucky, you find another compiler that implements another new language based on C with a different syntax for the "configuration" that provides the same semantics, then you can start porting from your own new language to that compiler's new language, and then maintain two implementations of that part of your code (erm, "configuration").

If you want to create a new language with better semantics, better invent one with sane, in-band, syntax. If you want to write C ... well, then write C, C is turing complete, so you can express anything you need in it, and every (non-buggy) C compiler will understand it.

> My real expectation, though, is that your compiler would actually run through your source files interactively, asking you questions where it thinks things are vague and recording the answers in its hint files, only actually doing a compilation pass once all its questions have been answered.

I think that that can't work. There are just so many places where it's somewhere between extremely hard and impossible for a C compiler to prove that undefined behaviour cannot happen that you probably would need a dozen annotations for every line of your code. Plus, keeping track of how the recorded annotations map to the code after it has been modified is extremely fragile, so if you wanted to be sure, you'd have to answer all the questions for a source file again after any semantic change you make.