3 ms·
As a long-time C programmer (20+ years), this quiz -- despite its flaws -- are a good example of how difficult it really is to write 100% portable C code. I of
by Teckla 14y ago
As a long-time C programmer (20+ years), this quiz -- despite its flaws -- are a good example of how difficult it really is to write 100% portable C code.
I often hear developers talking about how C is a simple language, but it may or may not be, depending on how you define "simple". For example, a written alphabet with only two letters -- A and B -- is "simple" to grasp (there's only two letters to learn!), but it would be very difficult, in the real world, to read and write such a language.
I think C is similar: "simple" in a sense, but very, very complex in another sense. C could use some massive clean-up, in my opinion. Much of its design was so that it could be ported to CPUs which haven't really existed in the wild in a long time in great enough numbers to warrant all the undefined and implementation dependent behavior.
The language could be hugely simplified, in the usage sense, if much of the cruft were jettisoned.
- AngryParsley 14y agoThat's a huge problem with programming languages: Designers can always add things, but removing stuff is hard. JavaScript is a great example of this. It still has automatic semicolon insertion, variable hoisting, and a broken comparator (==). Practically everyone agrees these are bad things, but they can't be changed. Doing so would break backwards compatibility, and there's a huge ecosystem of JavaScript programs that would need to be updated. Also, language users often rebel when language designers make breaking changes. Python 3 tried to remove cruft, and look how slowly it's been adopted. Instead of adopting 3.x, people backported the features they wanted to 2.x. I would love it if C had less cruft, but when I say that I mean, "I want C with less cruft, but with the same huge ecosystem of documentation and libraries and tools and debuggers and profilers that crufty-C has."
- taliesinb 14y agoThat's why I think the language Go is such a great development. The authors seem to have added only the minimum set of features that make the language workable for their initial needs. As a result, these features are largely orthogonal, and the rules are simple to state and learn -- even if they at first seem a bit odd (you have to cast all numeric types to each-other before they can interact). In contrast to Scala, another modern language I investigated recently, which seemed like quite a thicket of features.. some of which seemed just to be there to mediate the interaction of other features.
- deleted 14y ago[deleted]
- its_so_on 14y agoLet's talk about the solution here, since I'd like to know what it is! I'd like to hear what you guys have to say about it. ----------------- 1. Assumption: nobody is perfect and your programming language will have a gargantuan fault. since nobody is perfect, after the dust settles and you have a million users, your programming language will have a really gargantuan fault that is used hundreds of thousands of times throughout everyone's code. ----------------- 2. For this exercise let's make it extreme! Let's make this really extreme with something that's clearly braindead. Let's say in this language you have two comparisons for comparing integers, one for odd and one for even comparisons. (!!) =odd== which behaves like a normal comparison between two odd integers (5 =odd== 7 evaluates to false, and 5 =odd== 5 evaluates to true, but both 2 =odd== anything or anthing =odd== 8 is false, even 2 =odd== 2 or 8 =odd== 8) and =even== which is a normal comparison function between even integers and always false when either integer is odd, even if they have the same odd value. The normal way to do a comparison in this language is: (a % 2) ? a =odd== b : a =even== b ----------------- 3. aftermath Now, the language is at version 2.3 and there are HUNDREDS OF THOUSANDS of examples of the idiom (a % 2) ? a =odd== b : a =even== b throughout the codebase. It's a mess! Someone has the bright idea of cleaning up this cruft. Why not introduce ==, which compares an odd to an odd or an even and an even, returning true if the integer on the left equals the integer on the right, regardless of whether they're odd or even! ----------------- 4. how do you clean up? Great idea. Man, why didn't we think of this up-front. It's clearly much better. Well, nobody is perfect. It wasn't done this, better way, up front. NOBODY now argues that this way isn't better. But people have learned to live with this braindead feature. It's not just the one idiom either. Maybe you could search and replace (a % 2) ? a =odd== b : a =even== b with a new == -- but what do you do if someone uses =odd== or =even== outside that exact idiom? Maybe they have an arcane if-else clauses or functions that have bizarre logic and use these comparisons, which should not even exist. What do you do with it? Seriously. The dust has settled and you made a huge mistake. Now what do you do? - If you start over (3.0), it sounds like users will just backport your improvements. - If you introduce == WITHOUT breaking =odd== and =even==, people will keep writing code using =odd== and =even==, which is unreadable and wrong and a mess. - But if you DO break it, you break people's scripts and they will simply not upgrade past the point where it still works. If you find a security bug, you either have to backport it to the braindead tree or cut users off from it. And of course, in the real world, it's the == itself that is broken and doesn't behave the way it should, not these hypothetical braindead functions. so...what do you do?
- klodolph 14y agoEven languages that are explicitly designed to be minimal can be anything but. For example, Scheme. The call/cc function is a lot more complicated than it sounds, and it sounds complicated. People are talking about removing it from the "minimal" Scheme. (There are two versions of R7RS, the big version and the small version. If you think that call/cc is actually simple, then you haven't tried to write higher order library functions such as map.) And Scheme's syntax for numbers was invented by Cthulhu himself. (Python 3 was supposed to be adopted this slowly, last time I checked.)
- stcredzero 14y agoMuch of its design was so that it could be ported to CPUs which haven't really existed in the wild in a long time in great enough numbers to warrant all the undefined and implementation dependent behavior. A lot of the implementation dependent behavior is now expected. Not too long ago, I was taking part here in a brief debate in the comments for a Go language related post, and the programmer was up in arms that the Go compiler didn't transparently cast things for him. I pointed out that this would result in implementation dependent behavior, and maybe the design goal in Go was to eliminate that. His reply: That's what people should expect. >Of course< you should expect all these arcane things to happen when you port from one platform to another.
- taliesinb 14y agoI was taking part here in a brief debate in the comments for a Go language related post, and the programmer was up in arms that the Go compiler didn't transparently cast things for him I was that programmer, and I've now changed my mind. The whole 'less design is better' is always more palatable when it doesn't touch the things one is used to taking for granted (in my case, having a nice numeric tower). But the union of all the common such features gives you something like Scala, which is to me obviously over-designed. Go is more like the intersection.
- fauigerzigerk 14y agoI agree, but I also think that C isn't as complicated as these kinds of quizzes suggest. I've been using C for over 20 years as well, and I do know most of these arcane rules, but I don't rely on that knowledge much. I decided a long time ago that it makes no sense to trust myself and everyone who might have to maintain my code to always remember all these rules. It's a lot simpler and safer to remember a much smaller set of rules like don't mix signed and unsigned and just enable all the warnings. One thing I do that may be controversial is to prefer fixed size types most of the time. In my opinion, the decision to use a 16, 32 or 64 bit int type is not primarily a portability or performance issue. It's a decision driven by application requirements, and I want to express these requirements as explicitly as possible in my code.
- matheusalmeida 14y agoI think I don't understand... On one side, you say that C isn't that complicated but on the other side you say you just use a small subset because you don't trust yourself and your colleagues to understand all the C quirks... I think C is complicated with all the 191 undefined behaviors and 52 unspecified behaviors (source for these number is the paper that the author of the quiz wrote for specifying CSmith). One must master C before having absolutely knowledge that the code that he wrote doesn't fall into one of the two black-holes (undefined and unspecified behaviors). For instance, almost everyone that I ask, they tell me that dereferencing a NULL pointer yields 'Segmentation fault' but it's just not true. It's in fact undefined behavior. The other thing is the rules for strict aliasing... It's pretty much impossible to convert one pointer to another without breaking some of the C rules. The experts say type punning is the way to go but type punning relies in another not defined behavior. Reading an element from an union that wasn't the last element written is undefined behavior.
- fauigerzigerk 14y agoI didn't say anything about a small subset. The rules I use are not a subset of all those special cases, they are broader rules that cover lots of potential pitfalls and are easier to remember. But C is definitely more complicated than it should be, no doubt about it.
- mbq 14y agoWait wait, all questions in this quiz are not really about C but about the form in which numbers are stored in computer and consequences of that -- C just expresses them in raw way, but other languages also suffer from this quirks, either directly or via performance/accuracy jumps. EDIT: Ok, Ada has this done right.