- 44comments
- 143comments
- 21comments
- 205comments
- 51comments
- 10comments
- 39comments
- 69comments
- 223comments
- 235comments
- 12comments
- 43comments
- 149comments
- 25comments
- 48comments
- 170comments
- 15comments
- 12comments
- 125comments
- —discuss
- 87comments
- 2comments
- 8comments
- 107comments
- —discuss
- 246comments
- 24comments
- 144comments
- 15comments
- 16comments
Extensive discussion: https://news.ycombinator.com/item?id=9477006
Nice to see all the same arguments from just 4 hours ago being repeated again here.
Yes, blame the language.
We can either blame the language and change it, or we can blame humans and change them. I think the former is a bit more realistic.
Or we can help the humans improve.
You say that as if we even know what kind of human it would take to write safe C code. No specimen has yet been found.
Helping the humans improve means better tools, education, etc... and this isn't a binary thing, in that compartmentalizing it into the people or the language ignores the cost of rewrites and the use / reuse value of all the code bodies out there right now. Dismissing this simply isn't practical.
Augmenting C with things designed to work well with it can cut down on the use cases where C gets used and people aren't well equipped to do it. Great! That's improving the people while not stepping away from a massive investment and it's use value.
Then they die and you have to start over again. Humans haven't improved in at least 20,000 years.
It's not realistic in my opinion. Your web server and operating system for example will be built on a huge amount of C source code written by a huge amount of people; it's just not realistic to expect everyone to be careful enough that there's no buffer overflows in there.
Well, we've peaked on CPU performance, single threaded right now. Little tiny gains, but nothing like going from 1 to 3 and now just a shade over 4Ghz. (fastest single threaded x86 I could find recently)
Double that, and maybe we really can step away from things.
Why not blame the language?
There are plenty of languages available that are objectively more safe than C. Most of the security-critical memory-related bugs that are written in C (and C++) simply could not happen in, say, Java or Haskell.
By contrast, even though it is technically possible to write safe C, it is mind-bogglingly hard. The problem is too difficult to be solved even by automated static analysis, testing and fuzzing.
The reason those safe languages aren't used pretty much always boils down to either a) legacy or b) performance. Rust solves the latter, but the former is nigh intractable.
Simply expecting programmers to be better or more careful is not a viable solution. The aviation industry knows this - problems can almost always be attributed to a systemic cause, not the one-off mistake of an individual. Problems are fixed by making those mistakes impossible, not by reminding people not to do that, crossing your fingers and hoping for the best.
This attitude is spreading to other industries - primarily healthcare[1]. In the light of the ever-growing digital security threat, I think we should be making the same kind of efforts in software engineering.
C has its niche, but I think it is important to recognise that it has its tradeoffs. We should be trying to make things better.
[1] http://www.amednews.com/article/20100614/profession/30614994...
Exactly, if a language makes a mistake virtually impossible to make, why would you not want to take advantage of that? If there's even a small chance you can make a mistake, it's inevitably going to happen given a large enough project. For issues like security it's not scalable to just "be careful".
Also, as a programmer, I like to automate tedious problems away. I don't understand why a programmer wouldn't want to automate away such a enormously important issue.
It's a real dilemma.
Sure, the safeguards make your code 5% less performant; who cares, right?
Now suppose your code has a dependency, which has a dependency, which has a dependency, which has a dependency. And each level introduces a 5% performance hit. Suddenly your product is 28% less performant. This is why you end up with such nonsensical things as, e.g., the OWL API needing 2 gigabytes of RAM to hold an ontology that should take 200 megabytes max.
Do you have links to any benchmarks about this? I can't imagine bounds checking in practical programs has that much impact. For what impact it does have you have to weigh that against the impact of security exploits. Most languages with bounds checking have ways to eliminate bounds checks in certain scenarios as well.
people making noob mistakes in C and not learning gives me legitimate excuses to fire someone when I feel angry. Java? no excuse
Oh how dare we humans are so imperfect eh? We should crack the whip until those bastards learn to prevent their buffer overflows. Your attitude takes us nowhere. Yes, blame the language because that's what makes things improve. Computers need to adapt to us, no the other way around.
Not gonna happen.
We need close to the metal tools for a whole pile of things, and that's not going to change.
If anything, tools to help write C, or find errors, test, etc... are the more likely path.
That said, we could reduce the number of use cases for C now, and not lose too much, but that's not going to be the death of it by any means. More like a rational pruning.
Did you read the article? It agrees with you, and suggests Rust as a best-of-both-worlds option.
Yes I did, and interoperating with C isn't the death of C at all. My statement "That said, we could reduce the number of use cases for C now" covers the, "let's work with C and write more things in Rust..." scenario being proposed.
To actually replace C, whatever it is will have to be capable of something like the Linux Kernel, and make low level driver authors happy. Even there, C still works with assembly language.
There are still a lot of places where Rust isn't useable, especially when you're talking about things like embedded processors. Rust on the AVR, for example, requires very specific versions of llvm and clang to work, and even then, you have to write all of your IO code in a separate library, most likely in C. And it just rolls downhill from there. Wanna support the V850 that's found in a lot of automotive control systems? Nope. Rust doesn't quite have the ability to get down and dirty to do the kind of register tweaking you tend to do when you're using a processor with lots of IO you need to manage.
Ugh, as if we haven't been going down this path for three decades. We're still getting shit like heartbleed. When can we admit that path doesn't work and start trying other things?
Heartbleed is a symptom of bad programming, not a bad language. C is "less secure" because it allows the programmer to do possibly-unsafe things at their own discretion. The alternative is to flat-out ban those things. Which is appropriate for some use cases (the kind where performance doesn't matter). Inappropriate for others (the kind where performance does matter).
This is what designers think about all the time. How can a tool be designed so the unknowing user can't accidentally do something bad?
Heartbleed didn't happen on purpose, it was an accident. If you place all of the responsibility on the developer to catch, and be aware of, all possible weaknesses and attack vectors... Well you get today, that's what.
Okay, so your claim is tantamount to "every major C program is badly programmed", because every major C program has memory related bugs. If it's really bad programming, not a bad language, why is it that C is so much more often poorly programmed than, say, Python?
If it's C programmers, not the C language, then we should avoid C because that's the easiest way to avoid these terrible C programmers.
That's not the only alternative, you're just ignorant of the alternatives.
It's kind of like saying: trauma surgeons must be more dangerous than pediatricians, because so many more patients die in the care of a trauma surgeon than in the care of a pediatrician. It ignores the fact that you wouldn't send a pediatrician to such a difficult patient as you'd send a trauma surgeon to. You wouldn't use Python in a lot of the places you'd use C because the performance would be "shaggy puppy meets Godzilla" lousy.
Suppose I've established that the fastest way the computer can do X involves having the CPU (which only knows machine code, no magical languages) access a memory location without checking if it's in bounds. Either the language allows me to program that, or it doesn't. If it does, then Heartbleed-like bugs are possible. QED.
Alright, there's technically one other alternative, require the programmer to formally proof-verify that the code does as it's supposed to. I hope that this will become more practical within my daughter's lifetime (it probably won't within mine).
You can make any argument by analogy.
Suppose we don't suppose things that are wrong. Static type checking can check bounds at no runtime cost this in many cases. Like I said, your argument is based on ignorance of the alternatives.
I'm not hoping for 100% formal verification here, I'm merely hoping to be significantly better than C. That's a very low bar: C does very little checking. Why on earth would you be opposed to this?
In fact, I don't think we'll ever be able to 100% formally verify that a program does what it's supposed to. You can verify some things, like memory access, but in the end we'll never be able to 100% verify that the thing we are verifying is the desired behavior.
Look, I'm not criticizing the people who made C or the people who wrote tons of code in C. C was a great language in its time. But it's literally 4 decades old: it would be unreasonable to expect it to not show signs of age.
Trying other things is good. Interoperating with C is good.
But the reality is we've got a huge code body with a ton of use and reuse value out there. Can't just walk away from that.
And we've got the lower level, close to the metal use cases these higher level things we like depend on too. Can't really walk from those. Heck, Assembly Language still plays a part in drivers and other low level / boot strapping type activities needed to bring new tech online.
We've got major projects rewriting both OpenSSH and libgpg. Both in C. Nobody is saying it's easy to rewrite all of this code, but that is all the more reason to do it right, since we're doing it anyway.
Shit like heartbleed happens because OpenSSL was actively subverting system level libraries like malloc because it was too "slow". What we need are people willing to do the dirty work and audit libraries for practices that are horrible. Additionally, we need to make -Wall -Werror the default flags for C compilers, to make sure people are writing reasonable code. Furthermore, we need to convince C programmers that things like compile as you type are rather useful, and that they should stop clinging to toolchains that don't support it. In a sane world, the compiler would be a library like everything else, so ambiguous code can be handled much sooner in the process.
There are some things that none of these tools you mention will fix. As long as we're committed to C design flaws introduced decades ago there are some types of checks we simply won't be able to add.
If we're going to all the effort of learning a gigantic tool chain, why not learn a simpler language that gives us more checking than the tool chain does anyway?
I think that tweet is more about using Lex or Yacc instead of hand-coding logic to parse strings.
Lex/Yacc are great for parsing things like your own internal files that the end-user never directly touches. But if you really care about your users, there are certain times when you've just gotta bite the bullet and hand-roll a parser. Because when the user mis-places a punctuation mark, it's much better to give them a humanly-thought-out human-readable error message rather than a generic blob of unreadable gibberish.
Pathetic human frailty has nothing to do with the validity of syntax. The machines will do as we say, for the most part.
Don't be an ass, and don't whine about bullshit like extra curly braces and semi-colons. Know your memory map. Get your shit together.
So your solution is to come up with better humans rather than coming up with better programming languages? Yeah, that will work.
Oh, I see ...
Who writes this crap?
Mainstream media.
It's kind of fitting that HN is getting its language advice from TechCrunch now, apparently.
The problems described are accurate. From a modern standpoint, C and C++ are terrible. The only problem is that most new languages are more terrible along other axes, making them unusable for what C and C++ get used for.
The author is accurate that Rust may be a substantial improvement.
I don't necessarily want to program in Rust, which is why I am designing my own alternative, but I think if you are building safety-critical software than something Rust-like is a pretty good idea.
For my own experiments I am going more in the direction of giving the programmer auditing power, rather than just having the programmer have to silently worry about what code may or may not be doing.
I think what a lot of people don't realize is that, at least if you're writing Unix userspace code that mostly interacts with POSIX and/or kernel-specific interfaces, C remains the most convenient because the API/ABI standards are all designed with C semantics in mind, and a lot of wrapper/binding libraries in other languages are either too clunky or too abstracted, unless you decide to roll your own... and depending on the language, FFIs can be quite a nuisance.
The only languages so far that seem to have really gotten this are Go... and OCaml, to some extent (see the "Unix system programming in OCaml" document). Go in particular bypasses libc entirely by directly using the syscall interface, from what I recall.
Understatement. Every time I've tried to use a FFI I ran into either a show-stopping bug or a show-stopping feature limitation. My first few open-source contributions were patches for these bugs, as it happens, but the whole process was a massive slog that ended in repeated failure. I now loathe them with a passion.
Still, this all happened before LLVM-languages came around. Maybe things are better now. I look forward to the next time I have to use a FFI with both hope and fear.
That's nifty, but a big chunk of the reason for having C compatibility is that many higher-level libraries are written in it. How easy is it to talk to, e.g., the window manager using raw syscalls?
C tooling is much better these days. If you run your code under valgrind or address sanitizer with a good fuzzer, most of these concerns go away. True, you might not need that for a memory-safe language, but you probably still need to fuzz your parsing code if you want it to be any good. And enabling address sanitizer requires adding one flag, so it's not all that much harder.
Hm, this arguments sounds similar to the "you need to write tests with good coverage anyway" argument that fans of dynamically typed languages make when they're told that static typing catches many errors at compile time :-)
what a load of tosh
Every time I look at it, I have a very hard time taking Rust seriously. I really don't get whoever decided to use the shortest keyword names possible. It looks like a nice alternative to C, but wrapped in a horrible syntax. fn, f64, i32, u8, mut, mod, pub, ...
You are probably experiencing a syntactic illusion where it looks like C++ but then it looks all wrong. I've used Rust and it didn't take long to get acclimated.
All very true, I just think its still a little early to recommend Rust, personally.
inflammatory post. but it's techcrutch so what was i expecting?
this is the same as saying "armed concrete buildings fail more often then buildings made of paper and bamboo" while completely ignoring that all the world around them not even being possible without talented people building the armed concrete structures around the ego of whoever wrote this.
C! Made in AMERICA! (F--K YEAH!)
We can't be using any of those sissy languages made in Switzerland!
The real tragedy is that [Turbo] Pascal / Modula / Oberon / Eiffel never got any traction. We could have been ahead of where we are now for low / medium low level languages DECADES ago.
E.g. - Turbo Pascal:
* Checks array boundaries, but you can cobble up pointer arithmetic if you really need to squeeze something (it looks funny, as it should, but it converts into the same assembly code as ptr += size ; ptr)
references ("var" params) used safely as non-optional values in most cases, using pointers for parameters that are truly optional.* much stricter type checking and type range restriction allowed - most of which is only paid for at compile time, rather than run time.
* faster compiles, allowing quicker test cycles.
I suppose Ada fits in this group as well, but it was expensive in the late 80s.
Modern GC languages do well for long running application server programs, but they don't make good "transient" utility programs. We still need lower level languages for some types of programs.
Mobile could benefit from smaller memory footprints as well. I'm "gaming the game", but here are some tests on a 32 bit quad core setup, sorting by memory used for something that grinds through a number of connected objects as a surrogate for bulk data twiddling:
http://benchmarksgame.alioth.debian.org/u32q/performance.php...
Alas, the Pascal version used 3 times the CPU seconds that the (fastest, but 2x more memory) GCC version did. However, a lot of work has been thrown into tuning GCC. Also, there were 6 C/GCC solutions submitted for this problem, of which 3 were not even correct. Of the other 2 C attempts, one was about the same size and speed as the Pascal version, and the other was twice as big and three times as slow.
I don't need array checking, sometimes I might want to use a negative indices to access the last element
Problem is: C, while very powerful, ends up being a burden in today's complex software.
It won by being less verbose and "more powerful" (for some uses) than Pascal (amongst other things), however, the way software evolved it starts to pull down.
There's a lot of unmanaged complexity in C (and in C++ it just ballooned); things like Go, Python (and even Java) taught us that managing complexity is important
It's very easy to shoot itself in the foot in C, C++ gives you a laser scope on top.
Some software gets away with C (like the Linux Kernel) by being very careful with it.
https://twitter.com/id_aa_carmack/status/329210881898606593
Can C be salvaged? Maybe D is the answer?
What I would do: built-in strings into the language (C's strings are pretty much a syntax shortcut to a char array), safe strings, bounds checking, if you want an array of bytes you get an array of bytes, not a string. Type aware allocations (no more sizeof all around), maybe exceptions.
When viewed as a performance language, it makes sense why C doesn't come with built-in strings: there would be too much temptation for everyone to use those, instead of the particular implementation of strings most performant for the problem at hand (NULL-terminated or not? Stored with length or not? Support for Unicode or not? Stored in a hash table? A radix tree? Or just directly allocated with no attempt to remove duplicates?)
It's as silly as saying, "Different SQL string types are insecure, make everything TEXT!"
That's why nobody uses the C string functions, right? Oh wait...
If you need something else just use it, but for the majority of cases you want string functionality that is built-in and works (and hopefully is not a ticking time bomb)
Ada.
The ignorance in this article is way too high.
Blah blah blah. Another batch of anti-C/C++ propaganda by a technologically illiterate ignoramus. If C/C++ are too difficult for you then stay out of the way and use Ruby.
I'm almost tempted to pull out the old adage "if you can't stand the heat, get out of the kitchen". Yes, the C family of languages allows you to do many terrible things. It also allows you to do many great things. It is up to the programmer to decide what path to choose.
While the appropriate territory for the C family has decreased with the increase in processing capacity, there are still many areas where these languages are the right tool for the job. When another language family finally arises which offers the flexibility, conciseness and low-level access which characterises C (and its siblings, to a lesser extent) it'll be welcomed as a saviour, until that time they're the right time for the job.
I think the only way to end C is to port Linux to Rust/Nim/Julia/Scheme/etc.