9 ms·
C’s Biggest Mistake (2009)
- fithisux 3y agoOne of the best tech articles in 2009. Short and to the point.
- fithisux 3y ago14 years later nothing is fixed. But we still have D and an array of new developer friendly languages.
- psychoslave 3y agoSure, but I don’t see any of them even pretending to be a C replacement. I wonder if in several thousands year, mankind will have managed to get rid of C.
- tialaramex 3y agoWhat do you require from a "C replacement"? Zig in particular could scarcely do more to scream "I'm a replacement for C" without maybe asking WG14 to write "Just use Zig instead" in their next document.
- chongli 3y agoZig goes too far. It’s a radically different language with different syntax and very complex features such as comptime. People who want the issues of C fixed generally want to keep using C but without the issues.
- asveikau 3y agoI do think D bills itself somewhat as a C replacement. As does Rust, though it makes for a bigger change.
- NoZZz 3y ago[flagged]
- joshuaissac 3y ago> I mean the inability to pass an array to a function as an array, even if it is declared to be an array. This is possible for fixed-length arrays using 'myType (*myVar)[size]' as the argument type. https://stackoverflow.com/a/51527502 https://stackoverflow.com/a/51527502
- chongli 3y agoBut in reality is of limited utility. This fixes the size of the array in the function signature. If I want to write a function that returns the sum of all the integers in an array I would need to write a new function for each size of array, a non-starter. The annoying thing about this is that the array is just sitting there on the stack of the calling function. The size is completely known at compile time. But it gets thrown away as soon as you call a function.
- a_nop 3y agoSupplying the array length to such a summing function is not a big deal. The compiler is not likely to handle this poorly. Probably gets inlined. If the syntax is the problem, yeah, if you want first class data structures you might not like C.
- chongli 3y agoyou might not like C The title of the article is “C’s biggest mistake.” If you’re going to rebut the article, do so. Otherwise your reply just comes off as “this is the way it is, deal with it!” which is a pretty shallow dismissal.
- tialaramex 3y ago> This fixes the size of the array in the function signature That's what an array is. Fixed size. If we want to talk about a slice of some runtime determined amount of a thing then we need fat pointers, and C doesn't provide any fat pointer types so it's not a surprise to find it can't do slices.
- 3y ago
- 2h 3y agoGo did fix the C mistake: package main func foo(a []byte) { println(len(a)) } func main() { var b []byte // cannot use &b (value of type *[]byte) as []byte value in argument to foo foo(&b) }
- vimda 3y agoBasically every modern language has solved this...
- throwawaymaths 3y agoNot only that, but some have solved it while maintaining compatibility with null terminated strings. Null terminated strings, after all, are sometimes more efficient.
- zerodensity 3y agoCan't think of a single case where null terminated strings are more efficient. Could you give some examples?
- School-Cotton 3y agoIf you have to walk the string anyway, the null terminator has no downside.
- zerodensity 3y agoAccording to the bible (https://www.agner.org/optimize/ https://www.agner.org/optimize/) it's faster to use a loop with length than walking though a pointer so not having a length will make it slower to walk the string whole also making things like simd optimizations harder for the compiler to do.
- throwawaymaths 3y ago
- antiquark 3y agoA language from 1989 made a mistake? SAY IT AIN'T SO!
- sneed_chucker 3y agoTry 1972
- sedatk 3y agoProgramming languages had array and slice types since the 60's. It wasn't like C developers didn't know their value. As a matter of fact, C's relaxed behavior with pointers and arrays when it came out was PRAISED to no end in the 80's like it provided developers great flexibility to do whatever they wanted, and the compiler would get out of the way. It was thought of as a feature at the time. It wasn't an omission but a deliberate choice to do it that way. People only relatively recently started to care about security and maintenance cost of these features.
- akira2501 3y agoWell.. a large portion of the installed base wasn't running an operating system with anything approaching a "permissions model" let alone "dynamic memory" and there were several competing systems and architectures vying for the top. So, the desire and need for that flexibility was entirely warranted.
- FullyFunctional 3y agoAnd it was a great relief compared to my experience in, say, Pascal. You'll need a fairly advanced type system (Rust, Haskell, ...) to express the kind of stuff we wanted to do with static types and a very good compiler to make it efficient. We didn't have that until maybe mid-90es and trying to do it without that either led to very inefficient code or to breaking the type system. So C was [mostly] great, but today we have better options.
- deleted 3y ago[deleted]
- drekipus 3y agoA lot of comments are saying "other languages have fixed this" but i think the point is more that this is fixable within C itself.
- laxd 3y agoGetting into rust recently I think it's not to be undervalued how much a good built-in library has to say. In C there is so much coding just for small things that you take for granted coming from higher level languages. In rust, it's there.
- keyle 3y agoNot sure why you got downvoted for speaking the facts. Arguably the needs of the standard library of a language designed in the 70s compared to today are very different. That said, maybe new C standard should come up with all-batteries included standard library upgrades. On second thought, imagine the compilers snafu. I love C and I love Rust, for different reasons.
- Veserv 3y agoAs someone who works in C, C actually needs less in the standard library. What it actually needs is a proper import/module/build system to make it easier to stitch code and librarys together. The prevalence of header-only librarys attests to what a total mess it all is. A proper import system would massively reduce the amount of wheel reinventing because then it would not be fiendishly difficult to actually reuse code in a coherent way. Only after that does it make sense to start quibbling about what is included where and by default.
- packetlost 3y agoI'll second this. The biggest thing I think C needs (besides what the author of the linked article is saying) is proper namespaces and modules. It holds the language back so much. Tagged union types would also be really, really nice.
- Gibbon1 3y agoI've come around to the idea that first class types, tagged unions, and boxing and unboxing phat pointers would improve the language immensely. Also the standard lib and POSIX reminds me of a homeless persons shopping cart full of precious stuff they picked off the street.
- pornel 3y agoThe sad thing is that it's still not fixed, and probably never will. That article was from 2009. C11 didn't fix it. C18 didn't fix it. C23 didn't fix it.
- bwanab 3y agoHow can you fix it when so much production software depends on that behaviour?
- usefulcat 3y agoTFA suggests an additional language feature, not the removal of the old behavior.
- ActorNightly 3y agoIt doesn't need fixing. Local variables are stack frame dependant. It makes perfect sense to make an array a pointer when using it out of the stack frame. It forces the programmer to actually think about what is going on underneath.
- keyle 3y agoAsking the C nerds out here... Is that really C's biggest mistake? Edit: I just realised the article was written by D's Author! So maybe that is C's biggest mistake.
- thechao 3y agoI'm a big C proponent, via C++, I've thought about this article on-and-off since it first came out. My team uses C++ to define new container types & some type-safe translation stuff. If I think about it, our containers are — at their root — fancy fat pointers. So ... yeah ... Walter's right, IMO.
- msla 3y agoA lot of C's flaws are fixed in C++. C++ adds a number of its own flaws, but that's beside the point when discussing C's flaws from a perspective of knowing C++.
- aldanor 3y agoFixed but not enforced (which makes sense given compatibility with C). And that's often the problem, as each next "flaws are now fixed" iteration adds +1 method to do the same thing.
- AnimalMuppet 3y agoC's biggest mistake was originated in 1972 by people trying to create a language for writing operating systems, instead of being originated in 2000 by people trying to create a language that didn't allow you to make the mistakes you could make in C.
- pjmlp 3y agoThose people had plenty of examples since at least JOVIAL in 1958, that they decided to ignore to create they own thing.
- 3y ago
- oconnor663 3y ago"No proper arrays/slices" is definitely up there, but I'd nominate "no dedicated error handling" for the #1 spot, by virtue of how much trouble it causes compared to how easily it could be fixed. Go has a reasonable and remarkably lightweight approach here: add just enough of a tuple types feature to support multiple return values, and then make the rightmost return value an error flag by convention. Easy! No more "zero indicates success unless the return type is a pointer" nonsense. Bonus points for something like `error` that gives tooling a clue, but even that we could live without.
- kaashif 3y ago> add just enough of a tuple types feature to support multiple return values What's the difference between returning a two element struct and a pair of value and error? I never understood why "multiple return values" is a thing anyone should care about.
- achates 3y agoWouldn't you have to define a new struct type for every function return type?
- GeneralMayhem 3y ago1. In a world without templates/generics, you have to manually define a different such struct for every possible return type. Can be macro'd at the function definition, but it's ugly. 2. Without first-class support, it's very difficult to assert that the error is actually being checked. Consider: int someVal = getSomeVal(...).v; doSomethingWith(someVal); vs. (int someVal, error e) = getSomeVal(...); doSomethingWith(someVal); Which is easier to catch at code-review time, or even at linter time? In most languages that don't support multiple return values, both problems are solvable with templates or local equivalent - see, for instance, absl::StatusOr for C++ (https://abseil.io/docs/cpp/guides/status https://abseil.io/docs/cpp/guides/status).
- signa11 3y ago> 1. In a world without templates/generics, you have to manually define a different such struct for every possible return type. Can be macro'd at the function definition, but it's ugly. one trivial possibility/option is to define in-out parameters, and just return errors: <error-type/int/…> foo(T*, <params>) will that not be ok ?
- hahamaster 3y agoC is not a general purpose language, it was always intended to be used by people who want performance and control. If you want to pass a potentially large array by value to a C function, it's likely that you're using the wrong language.
- teaearlgraycold 3y agoWhat's large got to do with it? You can have a buffer overflow on a small array.
- noobermin 3y agoThat isn't what's proposed here, it's just passing the size with the pointer as one discrete type.
- hahamaster 3y agoYou're right, I was subconsciously replying to other comments about evils of passing parameters by reference.
- bwanab 3y agoI started coding in the 70s when C first came out. Conflating arrays and pointers was, to me at the time, a huge win. I agree it was a mistake in the long run, but given the state of the art at the time, it gave so much power to the high level programmer that up to that point only assembly level developers had. I was able to move code that up to then had been coded in assembly to C. That's the benefit that people today miss.
- glitchc 3y agoPassing array as a pointer is definitely a mistake. Not only is the size of the container lost, dimensionality of the array is lost as well. That a pointer to a pointer is syntactically the same as a pointer to a 2d array leads to a great deal of confusion in any codebase with a modicum of complexity. But likely neither of these is as big as letting void * represent any arbitrary construct, be it pointer or data structure or the universe itself. Finding references to void * in a codebase is akin to crossing the event horizon of a black hole.
- yvdriess 3y agoThat even horizon can be a useful feature, e.g. opaque objects (although technically you do not need void* for that).
- _8j50 3y agoI agree with OP but just for the sake of argument: You can use arrays as a member of a struct which also contains length, dimension and data specific details in other variables. If the problem is that this not being part of the language means everyone will do this their own way and will have to write a ton of extra code to support this, then yeah, that sucks but are most things C not like that anyways?
- xchkr1337 3y agoThere are many worse mistakes in the design of C, and some of them even got inherited by other languages, like switch statements.
- 0xfedbee 3y agoBut I don’t want a size parameter to be passed because I don’t necessarily (want to) have the size value at the call site. People on HN can cry all day about how bad C is and blah and blah. The truth is, C is the only language that gets shit done without getting in programmer’s way.