210 comments

[ 0.22 ms ] story [ 471 ms ] thread
c++. Its not going away.
The level of verbosity in modern C++ is almost approaching Java levels these days. I could see a simpler language gain favour.
The trick is to not use all the features.
It's actually the lack of features that's the problem for verbosity in C++. Features like algebraic types, pattern matching, Unicode handling – which are all part of modern languages – require bloated libraries and templating upon templating to work in C++.

C++'s apparent excess of features is mostly due to the fact that its memory model and type system have hundreds of edge cases that need handling. Compared to D, Rust and other newer languages, C++ never actually feels full featured (despite being horribly complex in some areas).

The beauty of C++ is that you can define an arbitrarily small subset of the standard that work as simpler language of its own!

Too bad not two projects can agree which subset.

Sounds like someone needs to rigorously define a good subset then write a tool to verify that a program uses only that subset.
Wow, that's huge. It's what everybody's doing anyway, but being standardized with big names and heavy hitters behind it makes it much easier to advocate and argue for.

Such an effort would be so much easier to advocate for in a C++ shop, and more importantly, very difficult to argue against.

This deserves a proper HN discussion. I've resubmitted it, it missed the front page the first time around:

https://news.ycombinator.com/item?id=10545921

(sorry for the karma stealing, lucozade totally deserves the karma if my resubmission takes off)

This hasn't been true since C++11.

C++11 is as terse as ML.

(comment deleted)
You got it wrong.

Before J2EE was a thing, there were something called CORBA and COM and mainly used from C++.

C and C++ have both passed the threshold of immortality. There's so many billions of lines of code in both those languages that the likelihood of either of them ever disappearing is very slim.

The question is about new development, and to what extent C and C++ are evolutionary dead ends. Nobody would design a language like C today, would they? They'd be laughed at.

They'd only be laughed at because they were accidentally recreating C and it'd be easier to just use C. C itself is a great language doing the job it was made for very well.
Again, the evidence of this is rather slim. It's basically impossible to create safe, code in C as evidenced by the fact that nobody has every managed it.

You're making the mistake of assuming that because you know something really well, that makes it good.

NASA got 3.8 million lines of safety critical code written in C for the Mars Curiosity rover by 40 engineers in 5 years. It can be done.

The talk on their coding standards, automatic code checking, code review and code coverage is well worth watching and listening to.

http://cacm.acm.org/magazines/2014/2/171689-mars-code/abstra...

But C wasn't made for safe code, it was made as a replacement for assembly language to implement Unix in. And that it arguably did well ;-)

Incidentally, according to Wikipedia, development of C started in 1972, the same year buffer overflows as a concept were first documented.

Use the right tool for the job, given the circumstances. Sometimes, the trade-off of switching away from C is reasonable and C is the wrong tool for the job. Sometimes, there is literally no reasonable option other than C. Sometimes, it's a finer balance and one needs to apply thought and knowledge and experience.

Use the right tool for the job, given the circumstances.

Use the right tool for the job, given the circumstances.

Use the right tool for the job, given the circumstances.

I know I said the same thing repeatedly, but around here when claiming that C is sometimes the right tool, you have to state "Use the right tool for the job, given the circumstances" more than once, and there will still be people saying that there is no use for C ever ever ever and everyone should use {fetish language du jour}.

I think the mistake you made was seeing your own concerns (safety) and assuming that because your needs require you to use something other than C, nobody should use C. I see this a lot in the programming world; people forget that they work in a tiny tiny tiny corner of the industry and assume their experience applies everywhere.

This is one advantage D has - it provides a path for gradual migration. It integrates so well with C and C++ that you don't need to throw away all th eold code and start again, you can do new devlopment on your existing project in D without too much pain.
C++ has reached the state of Cobol.

It's not going away just for historical reasons. There is too much code written in it which needs to be maintained in the next decades. I don't envy them who are forced to do that :-)

Why does anything need to replace C? It's been fine for years and still does exactly what it needs to do.
The endless, eternal, continual stream of catastrophic security flaws in every C program of note begs to differ.
I think this is not a serious question, but I'll bite. We're paying a hefty price for C in the form of buffer overflows, memory leaks, slow development, and other problems and will continue to do so as long as we run software written in C. If we instead switch to a language that doesn't have these problems, then we'll come out better in the long run.
It was slightly tongue in cheek - C is good at what it does, but I agree that there are plenty of good options going forward.

I just don't think C will be 'replaced' across the board though, but I suppose that's obvious.

Of the languages mentioned, I've only got experience with Go (which I use for APIs). Rust looks interesting though, I need to have a proper look at it.

We won't come out "better". We'll have made a trade-off. For some situations, it will have been a trade-off that benefits. For others, it will have been the wrong choice.

Just use the right tool for the job given the circumstances.

These aren't problems of the language. These are a result of having a design choice of full programmer control.

Having automatic cars is convenient and has its uses. But the argument that not using a manual cars will cause less road accidents is misinformed. It looks like that because common sense dictates that as it's easier to drive, more people will drive it easier. But usually the result is that now you have people on road who could not drive a stick!

Some things are meant to be written in lowest level possible. Programming languages are tools and it helps us to have tools for entire spectrum of abstractions. Electronic screwdrivers haven't replaced manual ones in 2 decades. That's not how tools work.

As far as direct comparisons go, these isn't any indication that raising the level of abstraction actually helps with more secure, bug-free code. Compare Java code written (in FOSS setting) with C code written in last 15 years. I bet you'd find C code more secure, more fast, more faster to refactor than a lot of Java code. So if Java was a systems language, would the world be better off if it replaced C? Probably no. Which shows that it's our infatuation with new shiny toys (languages like Go) that's driving our opinion rather than evidence.

C is like running around with scissors in your hand because it allows you to cut paper faster when needed.

Yes, its true but it is also likely to cost your eyes.

Java FOSS code is often faster, more secure, and a lot easier to reason about than equivalent C code. This is not really a language thing but a standard library thing.

The use of char array with a null termination for human readable strings is a terrible 'C' ism. And glibc standard String struct would have saved us all a lot of (security) issues.

The second is a community thing. Java uses defined behaviour to drive optimisation. C tends to use undefined behaviour to drinve optimisatio. The C case really trips programmers up.

Most of these things are not actual technical but more social issues. Computers don't care, it is us humans who do.

> Java FOSS code is often faster, more secure

But uses significantly more memory and requires a VM.

The VM probably is written in C, too.

There are AOT compilers for Java, some of them actually written in Java.

The reference JVM uses a mix of Java and C++, with code being migrated from C++ to Java and replaced with intrisics in each release.

Java 9 will bring Graal/Truffle plugins, which are a JIT compiler framework, written in Java.

Full programmer control and preventing bugs, security holes and so on are not fundamentally opposed. It's not like most programmers go to work trying to make sure their software has a certain number of buffer overflows in it. It just turns out that preventing that in C is really, really hard.

To take the car analogy further, whether your car is manual or automatic, seat belts and airbags are valuable. Neither of them compromises a driver's full control of their car.

Java isn't exactly a big step up. Compare instead old C code to Haskell or OCaml. I am pretty sure the latter comes out a lot better with respect to serious bugs.

Also I have real world experience with working with the same type of code in two different languages and seeing a clear difference. I've rewritten a lot of Objective-C code to Swift e.g. Objective-C as a language is much like C with similar problems as C. Just doing a straight conversion the Swift compiler picked up a lot of problems from my Objective-C code I had never discovered otherwise.

Lots of other people write about similar experience of getting significant bug reduction from moving to a much more type safe language like Swift.

Actually serious bug detection and prevention is not bad in C either. Most C code uses very well accepted design patterns which is very readable to a seasoned C programmer. Haskell and OCaml are better at easy reasoning of correctness of a program. Serious C bugs are around performance and security, not correctness.

The thing is, what a C programmer would consider a serious bug pertaining to performance and security, would not be fixable by Haskell being a better syntax. Ultimately it's the compiler that would bear the onus. Now generic compilers would always have performance issues and can't make everyone happy. That's the real problem here. It's easy to fix serious bugs (from perspective of systems programmers) in C than to fix them in Haskell. You have no control over compiled code or how it's going to turn out. The so called weirdness of C arises from the fact that non-seasoned C programmer do not understand why a C programmer is doing something. A weird C syntax usually is a signal to the compiler to write instruction code in a certain way.

It's not about correctness that a lot of C programmers are worried about. Well, at least not more than other languages. What we're worried about is what happens when rubber hits the road. It's very hard to do that from the driver's seat. Even Go, which tries to be closer to metal has issues around this. Things like Go, Obj-C, Swift are great where you simply want performance of machine code. But that's not the major argument to use C.

(comment deleted)
You seem to be talking about a very specific area. As I've eluded to earlier, there are clearly jobs where C is best suited, but C is hardly the best choice in most of the areas it is used. People are still doing GUI programming in C. That is a really poor fit for the language.

C isn't automatically easier to achieve high performance. Depends on what sort of problems we are talking about. If I remember correctly CouchDB was written in C/C++ originally and they switched to Erlang and got both much less code and higher performance.

But in something like a game engine were you want to be able to control memory layout and allocation C/C++ is a benefit. But Rust/Swift/Go allows you to do much of the same to various degrees.

At my work people write codecs and stuff and C is clearly a benefit due to its closeness to the metal. And as you say, yes they do write odd code at times because they know a lot about how the C compiler translates various constructs to assembly code. But this is specialist work. Most C coding doesn't involve this type of coding.

I think I just have to agree to disagree with you about correctness though. I had several years of C experience when I first tried Standard ML, and I manage to get a sorting algorithm correct on first try in SML, something I've never done in C. There will always be some stupid off by one type of error.

People have conducted studies of these sort of things and tend to measure better results for functional languages. One notable property of C programs is also that for any group of C programmers there is a huge variation in performance of the programs they write. The top C developers beat anybody. But average C programs are often slower than even average Python programs.

Agree. The unstated conclusion is nothing is close to being a C replacement. A good analysis of the languages anyway.
Because a large portion of massive security holes in recent history have been due to archaic C libraries that have security holes a-plenty. A lot of these issues that plague C don't happen in modern languages.

It's 43 years old (times have changed), and while I'm sure C still has its places, I think it's time to come to terms with the fact that people suck at handling memory manually and making sure type conversions are safe & a host of other security risks.

Other, safer languages can accomplish many of the same things C does these days.

Again, I'm not calling for the end of C, but in a lot of situations, it's just asking for it now.

There is a slightly disingenuity here. "a large portion of massive security holes in recent history have been due to archaic libraries that have security holes a-plenty".

The fact they are also C libraries is because that was the only real option of the time when they were written; rather like saying most car accidents were caused by black ones when the only option was a model T.

It is not true.

Before C escaped UNIX there were other systems programming languages available.

The manner in which it escaped Unix was through Microsoft and Borland, and I spent oodles of time evaluating other choices at the time. I could not get the boss to buy Ada, and everything was a compromise. Borland 'C' was super cheap and 100% available, as was Microsoft 'C' before it.
I kind of disagree.

Turbo Pascal and Apple Pascal ruled back then, at least in Europe. On Apple's case it was even the main OS language.

However with UNIX being adopted at work and universities, many wanted to be able to transport their work between home and work/uni. So people started to slowly adopt C.

I followed the same pattern with C++. Eventually Turbo Pascal wasn't no longer an option, so started using Turbo C++, C was just too primitive and unsafe already back then, vs TP.

At least C++ had some of the safety features I was used from TP, as long as one stayed away from C style coding.

Turbo Pascal was common before Turbo 'C' in the US as well. I personally was rather relieved to change from Pascal to 'C'. It's possible that that transition helped me to understand how to use 'C' safely.

With Pascal, I recall having to use more assembler.

I would say that from my vague memories, Turbo C 2.0 wasn't much different from Turbo Pascal 5.x and 6.0.

I had to use Assembly in both cases.

I was writing protocol drivers, and 'C' is better for that.
So don't use those parts of the library. We actually kept a mock-stub library to link against with the Bad Things missing to check before a release at one place. It was actually one object file and I dunno... 150 lines of 'C'?

I despair that "people suck at handling memory manually" :) It's not that hard, folks...

You're right. It keeps on giving us heartbleed, slammer, sasser, kernel null check eliding holes, and literally thousands upon thousands of other memory exploiting, remote executing, security breaking bugs.

But I'm sure, Real Soon Now(TM), if teams just adopt (best practices / better libraries / better code reviews / better static analysis tools / better testing) all those problems will be solved and C will be a great language to keep using.

After all, saving a few extra CPU cycles is totally worth breaking all SSL encryption and leaking private keys, quite literally putting the security of EVERY SINGLE FUCKING HUMAN WHO HAS EVER TOUCHED THE INTERNET in jeopardy.

So sure, let's just keep using C. It's fine, why change anything amirite?

(Sarcasm aside: In the general case it is not possible for humans to write security-critical code in C. So far the history of the internet has proven me 100% correct.)

Every one of those problems you mentioned occurred in C code, not C++. That might seem like quibbling, but many of those bugs are caused by C memory management bullshit like malloc(that) if (error) goto: free(that), which isn't a problem that C++ has. A scratch reimplementation of OpenSSL in C++ would probably be 1/3rd the lines of code and entirely devoid of both goto and malloc.
And a Rust implementation might be half the code and entirely devoid of classes of bugs that might be in the C++.
Rust's standard library aborts on OOM. That's completely unacceptable. More generally, I find Rust's error handling awkward --- the most common excuse for Rust's OOM handling is "Otherwise, you'd need to cart Result everywhere." Of course. That's why we invented exceptions decades ago.

The designers should have used traditional exceptions instead of trying to create something new --- the designers (just like Go's designers) had to go back and add exception support anyway.

I'd have liked Rust more if it'd focused on memory safety and less on being different for the sake of being different. I want a memory safe, non-GC language with traditional curly brace syntax, traditional types, and exceptional error handling. Modern C++ is a much better approximation of that language than Rust is.

It's definitely very important for some domains, but handling OOM "properly" is a really vague/impossible concept for most non-bare-metal programming. Modern operating systems will over-allocate/over-commit memory via virtual memory (so malloc usually succeeds), and kill programs when the physical memory limit is reached, and/or just grind to a halt by swapping.

For instance, I can happily "allocate" 100 terabytes of memory on my laptop (16 GB of RAM, 16 of swap):

  use std::{thread, time};

  fn main() {
      let _v: Vec<Vec<u8>> =
          (0..100_000)
          .map(|_| Vec::with_capacity(1 << 30)) // 1GB each
          .collect();

      thread::sleep(time::Duration::from_secs(10));
  }
Of course, if I actually tried to use much of it, bad things would happen, but the point is the allocations themselves never failed.

Bare-metal programming, like a kernel, will typically use the lower-level `core` part of the standard library, rather than the whole thing (i.e. `std`) because the kernel will be literally providing the interfaces required for most of std-minus-core.

(I think it would be really great if the standard library could be less harsh when an OOM is actually detected, and I suspect it can be tuned in future, but it's not a show-stopper for most tasks.)

> handling OOM "properly" is a really vague/impossible concept for most non-bare-metal programming

I strongly disagree. Handling memory allocation failure is trivial: throw an exception. It's also trivial to reserve enough memory to throw an exception. I honestly don't understand people who claim that recovering from OOM is futile because you need to almost always allocate memory to recover: in fact, you almost never do.

> Modern operating systems will over-allocate/over-commit memory

Windows is a very modern operating system and does not overcommit. (To its credit: overcommit is a terrible idea.) Even on overcommit systems, you can exhaust your address space and see allocation failures. No, 64 bits is not actually infinity. No, the whole world is not 64 bit. (Not every program even benefits from being 64 bit --- that's why the x32 ABI exists.)

> point is the allocations themselves never failed.

The resource you're allocating is address space. When you run out of this resource, your allocations will fail. On overcommit systems, you don't allocate commit charge until you access the memory. It's very difficult to explain to people who work exclusively on overcommit systems that "memory" isn't a single resource, but a set of related ones, each of which can be exhausted.

> I think it would be really great if the standard library could be less harsh when an OOM is actually detected

The only reasonable thing to do on OOM failure is throw an exception, like Java and C++ do. Error codes are too cumbersome even if you dress them up and call them "monads" --- a lot of code allocates, so if you used error codes to indicate OOM, you'd have to manually propagate exceptions from almost everywhere) and just panicking or aborting is too brittle, since you can, in fact, successfully recover from allocation failure, persistent folk myths aside.

Now Rust has both Result _and_ panic/catch_panic, which I think is both sad and hilarious, as it's going to lead to decades of confusion over which error reporting mechanism to use in a particular situation. (The Go designers made exactly the same mistake, as did the designers of the old java.io.File interface.)

It's a shame for such a young language to have that kind of baggage already. If Rust's designers hadn't been so stridently anti-exception in the first place, we'd have ended up with a much better language.

  > Now Rust has both Result _and_ panic/catch_panic
The forthcoming facilities for "catching" panics are deliberately hobbled so as to prevent them from being suitable for use as a general-purpose error-handling mechanism. What they're for is fault isolation, most specifically for preventing code from unwinding across a FFI boundary (which would result in undefined behavior).
catch_panic doesn't look particularly hobbled to me. Besides, I can insert an "FFI" boundary between any two parts of the program I want, and nothing can stop me. But it's moot: I'm not keen on using a language designed by people who are opposed in principle to exceptions, the cleanest form of error handling around.
You can read the comments on the original RFC for stabilizing catch support and see that the majority of them revolve around various ways of deliberately handicapping the API: https://github.com/rust-lang/rfcs/pull/1236

It even inspired a followup RFC for the purpose of codifying these restrictions in a brand-new fundamental trait: https://github.com/rust-lang/rfcs/pull/1323

Yes, but it's still progress toward the inevitable end result of traditional C++-style exceptions. That's the inevitable end state because the traditional exception model is simply the best one.

  > the inevitable
It's not inevitable in the slightest. Rust made a conscious effort to avoid exceptions for good reasons, and there's no reason to suspect that Rust will suddenly pivot on its heel in the opposite direction. Despite your attempts to paint this as a slippery slope, the unwinding-halting mechanisms are there to provide a safety net for people writing Rust libraries that expose C ABIs so that library code can fail gracefully without taking down the parent process.

  > the traditional exception model is simply the best one
Citation needed. :P The Rust community has long since embraced Result-based error handling; I don't hear calls for adding exceptions nearly as often as you seem to suspect. As to "inevitability", you'll be sad to learn that Rust plans on adding a mechanism that will enable applications to make panics impossible to catch, by disabling unwinding entirely and translating all panics to outright aborts (some argue that this should even be the default behavior of Rust code, but that won't happen any time soon). And considering that Mozilla disables exceptions entirely in Firefox, I see no reason they would pressure the Rust developers to add exceptions to Rust.

You seem to be taking Rust's approach to error handling far too personally. :P It is not Rust's position that exceptions are a blight that must be scoured from the face of the Earth. It is merely Rust's position that there are easier ways to achieve concise and composable error handling for its intended domain, given Rust's other features and safety mechanisms.

> Despite your attempts to paint this as a slippery slope

It is, though. I'm not[1][2] the only one who very much prefers the exceptional model of error handling. Once the ability to catch exceptions exists, people like me are going to write exceptional code.

[1] https://github.com/rust-lang/rfcs/pull/1236#issuecomment-127... [2] https://github.com/rust-lang/rfcs/pull/1236#issuecomment-128...

> > the traditional exception model is simply the best one

> Citation needed. :P

When Java, Python, C++, and Common Lisp all converge on the same thing, maybe that thing has something going for it. Part of my claim is subjective, but I've worked on systems that used everything from abort to error codes to tagged unions to exceptions for error reporting, and I've found the exceptional code by far the easiest to work with.

In exceptional code, I can write foo().bar().qux() even though foo, bar, and qux can all fail, and without any extra syntactic noise.

> by disabling unwinding entirely and translating all panics to outright aborts

I believe that's a mistake: it's a reprise of the -fno-exceptions debacle of the C++ world, where the ecosystem is fragmented due to fundamental disagreements on the correct error handling strategy. You'll get into a situation where some components rely on panics being hard aborts for correctness and other components rely on non-aborting panics for error handling.

> And considering that Mozilla disables exceptions entirely in Firefox, I see no reason they would pressure the Rust developers to add exceptions to Rust.

Rust is probably a fine Servo implementation language. Tellingly, Mozilla also uses an infallible memory allocator. I merely believe that Rust's design choices for allocation failure and error handling lead to it being a losing contender when compared to modern C++ for general-purpose systems programming.

  > Once the ability to catch exceptions exists, people like 
  > me are going to write exceptional code.
By all means, go ahead. :) Application code is free to do whatever it wants, and godspeed to you. Meanwhile, the restrictions on the catch API will be sufficiently onerous that library authors will continue to favor Result-based error-handling for their public APIs (to say nothing of the fact that some of their users may have opted to turn panics into aborts).

  > You'll get into a situation where some components rely on panics 
  > being hard aborts for correctness and other components rely on 
  > non-aborting panics for error handling.
Indeed, this is precisely why Rust decided to ship 1.0 with unwinding enabled by default, much to the consternation of those who wished unwinding to be excised from the language entirely. The language is defined such that if your personal `unsafe` blocks fail to consider exception safety, you run the risk of undefined behavior and thereby forfeit Rust's guaranteed safety mechanisms: http://doc.rust-lang.org/nightly/nomicon/exception-safety.ht... . Meanwhile, the fact that catching unwinding is all but unusable as anything other than a failsafe of last resort (and even then is only intended to prevent a total abort and/or undefined behavior) means that no library is going to resort to non-aborting panics for error handling, as mentioned previously.
> library authors will continue to favor Result-based error-handling for their public APIs

Except for the library authors who opt to write in C++ instead, of course. If you have to deliberately make a feature of your environment difficult to use, you're optimizing for the wrong thing. The Java experience shows that bad programmers will write bad code no matter how many safeguards you try to add to the language, so the only worthwhile "speed bumps" are those that help people who know what they're doing not accidentally shoot themselves in the foot. I cannot imagine an exception-catch block appearing in my code by accident.

Quite a bit of the discussion in the threads you mentioned has to do with flagging code as "requiring review" and adding "speed bumps" for "potentially troublesome" code. That's very worrisome, as it indicates that at least some members of the Rust community favor the Java-esque sandbox model of safety over the safety-catch model.

C++ has many flaws, but at least it never makes me feel like the language designers thought I need to be protected from myself.

  > the only worthwhile "speed bumps" are those that help 
  > people who know what they're doing not accidentally 
  > shoot themselves in the foot. I cannot imagine an 
  > exception-catch block appearing in my code by accident.
Rust is very much designed to help people who know what they're doing not shoot themselves in the foot. The risk isn't in a catch block appearing in your program by accident, it's the fact that exception safety is an invisible footgun that has potentially severe implications even for code that doesn't believe that it has any reason to concern itself with error handling in the slightest.

(The irony in all this is that Rust's approach can be interpreted as an attempt to return exceptions to their roots by relegating unwinding to exceptional circumstances, as opposed to the routine error-handling solution that they've become in languages that have chosen to embrace exceptions (e.g. Python's egregious `StopIteration` exception for loop termination).)

> return exceptions to their roots by relegating them to exceptional circumstances

Python does it right. I've never bought the argument that "exceptions are for exceptional circumstances". If you use error codes for some errors and exceptions for others, all you do is confuse people. The definition of "exceptional error" is subjective, after all.

As far as I can tell, the advice to use "exceptions for exceptional circumstances" originated in C++ circles in the 1990s, when support for exceptions was bad and throws were slow. The thinking was that you could efficiently use error codes for commonly-encountered errors and still get some of the syntactic benefits of using exceptions for rarer errors. Also, if you were using a compiler without exceptions support, you could turn your exceptions into aborts while not aborting just because a file doesn't exist. You can see vestiges of this thinking in the iostreams API.

Somehow, this performance hack morphed into commonly-accepted dogma. I don't accept this dogma. Exceptions are for any situation that a function can't meet its contract. In Python, if an iterator can't supply its next element, it can't satisfy the contract, and the exception tells you why. I don't think there's anything particularly wrong with that.

I suppose we'll have to agree to disagree, then. :)
> Handling memory allocation failure is trivial

The problem I'm talking about is allocation failure and OOM are not the same: handling out-of-memory reliably is a lot more than just checking for NULL in `malloc`, as I demonstrated. There's no guarantee that allocations will fail when they "should" and so you'll only learn that you're beyond reasonable limits when you touch enough pages that the operating system starts killing programs (possibly yours, possibly others), or when the user cannot actually use their computer in any reasonable manner.

> Windows is a very modern operating system and does not overcommit

Yeah definitely, it's why I was sure to mention the problems with swapping (sure, the memory is allocated and usable by the program, but in slow motion; not so great if you actually want to use the computer).

> The resource you're allocating is address space. When you run out of this resource, your allocations will fail. On overcommit systems, you don't allocate commit charge until you access the memory.

Yes, running out of virtual memory is one way for allocations to fail, but, as you say, there's a variety of different systems at play here. Only failure in one of those systems (requesting virtual memory/address space) is handled by checking for `malloc` returning NULL, and so focusing on just that is missing the forest for the trees. Presumably the overall goal is to handle memory exhaustion gracefully, not to check the return value of NULL (which is just one part of the former).

That some operating systems lie about resource commitments is no reason not to provide reasonable facilities for reacting to allocation failures. By doing so, you make it harder to write well-behaved programs for systems that don't overcommit --- besides, no system overcommits address space, so malloc can always fail.

It's true that even with reasonable allocation failure reporting on a non-overcommit system, you can use too much memory and make life unpleasant for users without actually seeing allocations fail. Bounding resource use is important regardless. That's an issue of good behavior, however. Even absent good behavior, programs should at least be robust.

One of the reasons overcommit bothers me so much is that infects programming communities with the idea that resource consumption doesn't matter, since if you use too much, you're just going to get a SIGKILL anyway.

If you throw an exception, what would the resulting recovery mode even /be/, aside from clearing out unused memory (never mind that just finding all of your allocations is a nightmare in and of itself)? And how would this actually work in a non GC world where functions can allocate and free at any time -- ie, you are working on a team and can't know the state of every thread, task or chunk of code at once?
> If you throw an exception, what would the resulting recovery mode even /be/

Unwind the stack and present an error message or take other appropriate action, just as we would for any other error. By unwinding the stack, we release owned resources, and some of those resources happen to be memory blocks. What makes memory so special?

> just finding all of your allocations is a nightmare in and of itself

Huh? In a non-GC system, if you can't find your allocations, you're leaking memory.

My point about finding the allocations is actually a bit poorly put: not all parts of your program may be ready to release memory it has held without losing user data in the process.

Memory is special insofar as it is a core resource that has so much contention that OOM situations may not be directly because of your application, and recovery may not even be possible without allocation.

I'm slowly coming to realize my argumentative point is losing ground -- this is great! :-)

You're not supposed to use the stdlib for baremetal programming.

> instead of trying to create something new

monadic error handling isn't new. It's an old feature used by many languages, and preferred by many over exceptions.

> You're not supposed to use the stdlib for baremetal programming.

I don't think it's useful to partition the world into microcontrollers and "LOL, memory is finite?" domains. Allocations can fail for normal programs, particularly when imposing subsystem-specific allocation limits or when running in small, crowded address spaces (e.g., mobile devices). It's often useful to be able to recover from this condition without completely killing the process, since process death is much more annoying for users than a specific task failing. (Wouldn't you rather see a video not play than see your entire program die?)

Rust's libcore wasn't split out for "LOL, memory is finite" domains. It exists so that you can write Rust programs that restrict themselves to doing no dynamic allocation whatsoever, as needed for environments where an allocator simply isn't available or allowed.
My point is that I want to write programs that do use dynamic allocation, but also handle failure of this dynamic allocation in a reasonable way. Right now, Rust's philosophy is that you can choose whether to use dynamic allocation, but if you do, it'd better be an infallible allocator.
On OOM, what should happen other than a hard abort? On most VM systems, malloc and friends oversubscribe what is actually available. What possible recovery mechanism can you implement to prevent this from happening?
> On OOM, what should happen other than a hard abort?

On a web server, 500? On a document editor? "Sorry, couldn't add attachment". What to do in response to error is application-specific. My point is that memory is not special and there is no reason to treat memory errors differently from other errors. You wouldn't abort if you run out of disk space.

> On most VM systems, malloc and friends oversubscribe what is actually available.

Windows is a common non-overcommit OS. Even on overcommit systems, it's possible to exhaust a process's virtual address space. (Overcommit systems also have ulimit -v.) If you do run out of either address space or commit, it's frequently the case that you can just stop what you were doing and display an out-of-memory dialog. The process of "stop what you were doing" can certainly free enough memory to keep going.

http://www.gotw.ca/publications/mill16.htm

So Herb Sutter mostly agrees with your view, but my question is a corollary, and something he touches on: how do you keep going if you stop what you were doing? The process of recovering is not straightforward, and if you have threads running, that process is utter chaos, if not outright impossible in some languages. Even on non overcommit systems, the user finding another way to work around a memory failure is useless because the system is already hosed to the point where a small memory allocation will fail. Either way, the situation is so bad that the user does not have the ability to recover what was just done in your application without closing your application in the first place -- which, incidentally, leaves the user stuck in exactly the same place as if your application aborted.

The big idea here is that the OOM condition may not be because of your application.

> how do you keep going if you stop what you were doing

You unwind. If you have threads, you reliably signal for them to stop (using resources you've set aside for the task), then you join the threads and continue unwinding. I think it's perfectly straightforward.

> Even on non overcommit systems, the user finding another way to work around a memory failure is useless because the system is already hosed to the point where a small memory allocation will fail.

Most serious operating systems have a way to say "run this process in this special environment where it can't allocate more than X MB of memory". (Some examples are NT Job objects, FreeBSD jails, Linux cgroups, and plain old ulimit.) In this kind of environment, you can certainly run up against limits for your process without the system having been rendered unusable.

> because the system is already hosed to the point where a small memory allocation will fail

Absolutely not the case. Imagine a state where a 100MB allocation (e.g., for an image) might fail (say, due to virtual address space fragmentation), but a 10 byte allocation would work just fine. The same principle applies to system commit considered globally instead of virtual address space considered per-process.

> the situation is so bad that the user does not have the ability to recover what was just done in your application without closing your application in the first plac

If that's the case, the application is just badly coded. Memory is not special. It's just another resource. If you can't keep track of resources and release them when they're unneeded (as they would be after an error), you're doing something wrong.

> http://www.gotw.ca/publications/mill16.htm

That article is factually incorrect. Sutter claims that "On...Linux, memory allocation always succeeds. Full stop." That's false, as a ten-line C program that calls malloc in a loop can demonstrate. You eventually run out of address space, especially in a 32-bit process. (There's a very popular overwhelmingly 32-bit Linux distribution out there called Android. You may have heard of it.) Sutter also claims that on other operating systems, overcommit is configurable. It's in fact configurable under Linux too. Linux can run in sane, non-overcommitting mode.

> Every one of those problems you mentioned occurred in C code, not C++

The title of the post talks about C, not C++.

While C++ certainly makes it easier to write safe code, you still need to be quite careful. C arrays, manual memory management, dangling pointers and all kinds of other unsafe constructs lurk behind the thin veneer of modern C++ style.
No way, C++ removed some C problems but just added a whole host of its own problems, that don't exist in C: operator overload hell, static initialization and deinitialization hell. Calling virtual methods in constructors blow up. I programmed C++ for 13 years and must have had rose tinted glasses on. I kept reading books like Effective C++ thinking that my bugs would go away as soon as I learned all the intricacies of C++ and best practices. I realize now that I mostly program in other languages that the enormous amount of knowledge you need when writing C++ safely simply isn't needed in most other mainstream languages.

If you think C++ is the answer to C's problems I think you suffer Stockholm syndrome. You've gotten so used to all the issues in C++ and started thinking about them as normal, so you stop seeing what a mess this language is.

Nobody is going to make you overload operators, do work in constructors, or throw exceptions. Restrict yourself to the subset of C++ that you prefer.

By comparison there is no subset of C that lacks malloc/free.

In practice most of us are restricted to the subsets (note plural) chosen by the people who wrote the original systems we work on.
But then you can't move to another language anyway. If you can move to another language (say if you start a new project), it's worth moving from C++ to C++11.
And a new language is magically going to solve all the problems you mentioned and do everything c can at the same speed?
Not magically, but with a lot of technical effort Rust does solve those problems and at the same speed.

As in a Rust compiler will generate equivalent assembly as C in equivalent cases. With practically for now some places where Rust will win and some where C will win performance wise. But there are no practical reasons for Rust to be slower than C or C++.

Could you rewrite linux kernel in Rust?
Yes. However, writing a linux-like kernel that is not 95% `unsafe` code would be a lot harder than just a straightforward syntax change of C to rust.
Sure, but it probably wouldn't make sense to. Instead, you'd be better off doing like the Redox folks and designing your own Rust-based OS, with plans for a Linux-compatible userspace: http://www.redox-os.org/
C was dog slow in its early days and there were safer systems programming languages available outside the UNIX world that were equally fast.

What has gotten C compilers to generate the code quality that have nowadays is 40 years of work in compiler optimizations targeted to improve C compilers code generation.

I still wouldn't blame the language for the errors its users commit. Its like blaming Java and PHP for XSS and SQL Injections. Unskilled developers will always write insecure code, despite what language they are using.

Edit: To clarify my point, "A fool with a tool is still a fool"

>Unskilled developers will always write insecure code, despite what language they are using.

They - uhh I mean - we won't if it's impossible.

Then explain me how you would make an Language inherently immune to string injections.
You can make a language inherently resistant to string injections. You only need library authors to cooperate and an extension to your string type like Ruby does, to have your language reject thoughtless injection vulnerabilities.
Its possible, but if these solution make an language that secure, why haven't them caught on yet?

Back to my point: Tools can't replace knowledge. A fool with an tool is still a fool.

Are you claiming that unless we erase all security problems, it was all for nothing?
(comment deleted)
What other language would someone use to write a kernel or driver? Even if you use a higher-level language for most of the logic you'll likely want the core to be C -- amazing considering the language is nearly 40 years old. C is, to me, a systems programming language. Writing code that handles any significant amount of user input in the language is a mistake I believe. Note that this doesn't include C++ which has more modern constructs.
That's Rust: it aims to be a viable replacement for C in bare metal and high performance code including drivers, kernels, embedded and all of those areas where C used to be the only game in town. It should do everything C does, but safely and without performance penalties.
Today Ada, Rust, Spark, C++, ATS.

Eventually Swift, Systems C# (if it ever comes out MSR), D, or any other language.

You might be surprised that NeXTStep used Objective-C for device drivers in the kernel.
That is pretty cool. Shows some of the versatility of Objective-C. I was also surprised that a low level API like Metal also uses Objective-C.
> After all, saving a few extra CPU cycles is totally worth breaking all SSL encryption and leaking private keys,

I'm afraid that these few CPU cycles do make a difference.

Throughput is the number one concern for thousands of network operators and service providers. They spend millions so you can get your content and not "509 Bandwidth Limit Exceeded".

You can't just go and replace all efficiency critical software by something that runs maybe just 10% slower.

It is 100% possible for humans to write utterly secure code in 'C'. The vast majority of practices which make code not open to memory exploits were common in the 1980s - the late '80s, anyway. Yes, there were virii even then.

Now, is this common? I have no idea. A great deal of 'C' code never sees the larger Internet anyway.

> Why does anything need to replace C? It's been fine for years and still does exactly what it needs to do.

well, for one the h/w model for one has far progressed beyond what the state of the art was during C's genesis. for example with the advent of multicore machines trying to use C's facilities to exploit available h/w resources becomes quickly unwieldy. witness the rise of event based approaches f.e. libevent and friends, or the rise of lockfree mechanisms etc. etc.

I'd bet my money that C will outlive them all.
Yes. C has the lowest abstraction depth without going into platform-specific details like asm. LLVM is the only thing that could compete with C on that level.
You probably know already, but just for anyone that doesn't, Rust uses LLVM to compile its machine code.
Properties of an language are not necessarily inherited when compiled. LLVM Code is not bound to Rust's memory access restrictions.
The Rust developers specifically tailor the compiler to generate LLVM IR that resembles Clang's generated LLVM IR.
Cobol is still around.
Depressing to read. Somehow I can not find a language I really like :-(
Me too. I think people generally prefer to stick with the evil they know.
I miss Delphi more and more. The language is ok-ish but when it comes to rapid Gui development it still runs cires around everything else.
Well, one of those things is not like the others.

Golang competes more with gc languages/runtimes like Python/Ruby/Nodejs. To a lesser extent it may compete with Java JVM. (However at this point in time, the JVM GC technology is still far ahead of Go's GC.) If one is writing a networkish service such as REST API endpoint, Golang's combination of language featurs & quality libraries (http) is positioned very well for that. Go isn't suited for system drivers or tight loops that depend on controlling exact memory layouts. I've heard several times to think of Golang as a "DSL for networking apps" and I think it's the best succinct soundbite for that language.

That leaves D-minus-the-gc and Rust which Andrei Alexandrescu provided very reasonable analysis. I don't think either will replace C. In 1995, many predicted that Java would supplant C++ and that never happened. For the performance domains that C++ was good at (e.g. AAA games, commercial software like AutoCAD and MS Office), it became even more entrenched. In terms of being forced to make bets, I'd say Rust has a better chance than D because Rust has the momentum behind it that D never had.

Plus, as Andrei says himself, D has a GC and it's impractical to work around that in D. So, from that point of view, only Rust can compete with C/C++.
Right. I clarified that I meant D's usage explicitly avoiding the historical GC. I'm not a D expert but it looks like the GC obstacle is mostly in the libraries and not impeding the language syntax.
It's a whole-ecosystem issue. There are plenty of built-in features that happen to depend on GC, and while the ways to eliminate GC use are only increasing with time, the "idiomatic D style" is left in doubt when it's so dependent on allocation strategy. Precision choices for performance are characteristic of D - you have a lot of options to type or annotate your code towards a certain envelope of performance, or ignore almost everything and leave it to the GC. So this is not an unfamiliar problem, but it's a point of friction in the same way that borrow-checking poses friction for Rust - the friction may be centered on what you want for your problem domain.

If nothing else, you can write C in D, in a roughly similar way to how you can write C in C++ - the features are there, and so are the libraries.

> Golang competes more with gc languages/runtimes like Python/Ruby/Nodejs.

I still cannot even grasp this trope. Seems like some try to apply "fake it till you make it" approach.

To me, coming from Python and Node (and a bit Ruby) development it seems as a completely opposite direction -- similar to going back to C++ or Java (where I started myself).

If not for the quirky syntax and lack of generics I would personally pose it as a replacement for the C++ itself.

Rust on the other hand seems to me to be the most promising out of these three as a systems language.

>I still cannot even grasp this trope. Seems like some try to apply "fake it till you make it" approach.

It's not a fake trope. There are tons of blog posts from programmers describing experiences of switching from Ruby+Rails to Go, or Python+Django to Go, or Javscript+NodeJs to Go. Some defections were high profile such as Nodejs uber-contributor TJ Holowaychuk switching to Go.

Compare that to virtually zero notable stories of C++ projects switching to Go. If people are using C/C++, they very likely depend on it for the performance characteristics and therefore switching to Go to suffer a speed penalty makes no sense. On the other hand, people leaving Python/Ruby report performance gains. That's why the reality on the ground looks the way it does.

    Compare that to virtually zero notable stories of
    C++ projects switching to Go.
A lot of projects at Google have switched from C++ to Go, and the people I know who work on them are pretty excited about working in Go. Here's a blog post by a coworker who leads the Chrome Data Compression Proxy project:

http://matt-welsh.blogspot.co.uk/2013/08/rewriting-large-pro...

Thanks for the example. I think your coworkers' rewrite further reinforces the "sweet spot" for Go.

The transcoding was left as C++ but the other stuff including the networking was rewritten in Go. That makes sense to me because transcoding is performance intensive and cpu-bound instead of io-bound. (E.g. CPUs pegged at 100% while bytes being read at a slow 10MB/sec.) In other words, if people tried to rewrite ffmpeg in Golang, a conversion job such as avi to mp4 would run slower.

If Google's internal cpu-bound projects switched from C++ to Golang, that would be a very interesting data point. In other words, I don't expect Google would switch their machine-learning algorithms scanning petabytes of data from C++ to Go (or create greenfield machine learning projects using Go instead of C++).

Well... you know, G+ is full of Google Employees...
Performance is not always the most important factor.

Also I don't know about Ruby but Python is moving really fast with PyPy.

We also have Cython. This is where I'd go when the extreme performance is needed. This way you can avoid compromising on other important factors (libraries, accumulated know-how, even syntax and development tools).

In case of NodeJS it's even more baffling.

> Performance is not always the most important factor.

But then why would anyone choose C++ for such a project, in 2015? (Aside from people who only use C++ and therefore wouldn't use Go either.)

(I can think of a number of other reasons, like exposing C interfaces or interoperating with GC'd languages, but I don't see how Go fits these things any better than most other GC'd languages.)

A lot of it is due to library support; C++ has libraries in physics and graphics haven't yet been written in other languages.

Another is the lightweight possibilities for C++ makes it possible to install and run good apps on tiny machines like Pis, where installing Java can be much more challenging.

C++ is also a great language for iOS and OSX development for those who are not satisfied with Objective-C or Swift.

If you use C++ instead of Objective-C or Swift for iOS/OS X development then it is just because you refuse to learn something new. The only use for C++ on iOS/OS X would be algorithm heavy code. C++ is a poor language for dealing with GUI or higher level concepts in an app.

Compare the elegance of stuff like Core Data, bindings, target-action, undo framework, predicate filter using Objective-C with how kludgy stuff like that ends up in C++.

I know because I have tried implementing similar stuff in C++. It is possible but it looks like shit.

I certainly agree with you for using platform-specific languages for platform-specific features. But I much prefer to write the main logic of an app in C++ and use Swift as the glue to the UI rather than use Swift for everything. I'm not yet sold on Swift, and being unable to take the code to other platforms is also a strike against it, for now.
One huge reason to use C++ on iOS is to avoid platform lock-in and for code sharing. How can you miss such a blindingly obvious reason?

And it is right on par with other languages when it comes to GUI building as Qt proves. However, something like QML in conjunction with C++ will be much more flexible and pleasant to use than any of C++, Objective-C or Swift.

CoreData is widely considered to be more trouble than it's worth it, as soon as you want to do some serious work. Predicate filtering... maybe I am missing something, but I'd pick <algorithm> + lambdas any day over that kind of magic. I have used Objective-C to write production code, and with few exceptions, I would consider it anything but elegant. It's a hodge podge of concepts thrown on top of eachother that's finally and deservedly being put to rest by Apple.

People also seem to underestimate the performance difference. Sure, Go is around 20% slower than unoptimized C/C++ (at least, with a numerically heavy algorithmic trading library I use that I've ported to Go). But when I use a great C++ compiler that vectorizes and gives me hints to improve cache performance (eg; Intel's compiler) it's often 2-3x slower.

In a tight loop, you can't afford to have a gc or green-threads or a runtime for that matter. You want excellent cache performance, minimal context switching, and very predictable memory access patterns.

Manual memory management is here to stay.

Don't get me wrong, I love Go (for the right uses) but it's just never going to be a replacement for C/C++/Fortran for high performance code.

I've actually considered Go for a personal project over my usual Python - the deployment simplicity of Go (a single executable) being a big attraction.

Where I am puzzled is people viewing Go as something comparable to C/C++ - it seems on a completely different level to me.

We have to thank Microsoft and Oracle for C++'s comeback to the news.

Microsoft for their work supporting the standards work, C++ conferences, push to improve language's safety. Also the change to back to native since the Longhorn failure that has switched focus to C++ and driven .NET to improve its AOT story, starting with Windows Phone 8.

Oracle by dropping the ball on Java support (JIT and AOT) for the mobile OSes, making C++ the only option to write portable code across all mobile OSes.

As for Go suitability for real systems programming, as a language geek and former Oberon fan, I think the day someone shows a Go bare metal runtime on top of something like Raspberry PI, the opinions will change. Thesis idea. :)

> making C++ the only option to write portable code across all mobile OSes.

Objective-C is also an option. Last I checked there were at least two options for ObjC on Windows and Android. More on Android, IIRC.

For many of us it is not an option, if it isn't in the official SDK.

Since many years I only work with platform languages.

So Google doesn't offer it on the NDK, it isn't an option on Android, even if third party do make it available.

Microsoft still isn't fully done with their clang integration, so still not an option as of today.

That is a valid choice. However, I think there is a difference between "that's not an option for me because of my preferences" and "that's not an option, period".
> "that's not an option, period".

That is the answer we get from customers. Dev machines are managed by their IT.

My preferences are the customer preferences.

(AAA games, commercial software like AutoCAD and MS Office), [C++] became even more entrenched.

If you're building Windows desktop "productivity" software, your options are basically which version of the Microsoft C+ API you want to work with. Microsoft are trying to migrate people to C#, and there are a few Java desktop apps (mostly java IDEs like Netbeans and Eclipse).

Similarly for (Windows) games: C++ is the only realistic option, although smart developers will embed a scripting language for the game logic (eg Lua for WoW). If you don't embed a language, the configuration system ends up being a badly specified Turing complete mess anyway.

So I wasn't really involved in tech in 1995, but it seems like at that point C/++ was the only mainstream option for writing code.

Hell, PayPal wrote their web app in C and still maintains it.

I would say that besides the niche that C/++ is in now, Java (and GC languages in general) did win.

"Win", "die" and other such terms are nonsensical when referring to programming languages. What happens in reality is that the new language carves itself a niche, taking more or less from the market of the old language.

And Java has carved itself a really nice piece of the pie, but it's unlikely that it will expand any more, because it's already dominating in its target niches and doesn't have much to offer where it is not dominating.

What a fantastic, thoughtful post. If anyone is skipping to the comments here based on the title, you should read the article, not least because it's by Andrei Alexandrescu.
D is my favorite. My problem is lack of IDEs and I do not count Visual D as one of them since it requires Visual Studio which is heavy and not crossplatform.. If they could go with Visual Studio Code (when it matures) or KomodoEdit which are cross-platform and free (bias on KomodoEdit) I would be all for that.

Until then I put my bet on Mono-D and DDT.

In any case, this month is the D month for me. Enough is enough with C++ and I am thankful to them because they made an amazing replacement.

I use Xamarin Studio (Mono-D) daily for programming in D on a Mac and it is a very capable IDE, at least for what I do.
Visual Studio 2015 Community edition it's far more lightweight that for example Eclipse.

I just re-attach to D for doing some stuff, and I found that DUB and VisualD just works very fine. And I'm a guy that in 75% of my time running on a GNU/Linux...

If C++ couldn't do it, D won't. They are of the same ilk.

Go kinda is already, but is too sucky on too many levels to really break through.

Rust is still alpha and seems to be going backwards at times, but looks like a strong contender.

Assuming Go fixes its many problems, and Rust is eventually delivered, I think they will both have a strong role to play, Go in the networking/systems space, Rust in the large scale app development space (like making a browser).

But C will still be around.

Rust isn't alpha anymore.
Go is not sucky. It is fantastic at what it does. I really see it as a valid replacement for all sucky frameworks like:

Django/Rails Sinatra and so on.

These frameworks do injustice to their languages :

Rails hurts Ruby, Django hurts Python, Sinatra hurts Javascript.

JavaScript has a lot to offer but in the distant future. An even then it relies on slaves building pyramids.

> Go is not sucky. It is fantastic at what it does.

Go is fantastic at what it does well, which is lightweight concurrency (with a synchronous api), something that no other compiled, imperative language offers.

But I haven't spoken to a single Go developer (and I've spoken to a few) who don't hesitate to tell me how sucky it is in many, many other ways. I've heard the phrase "I'm really starting to hate Go" more than once or twice.

>Rails hurts Ruby, Django hurts Python, Sinatra hurts Javascript.

Is there some JS framework called Sinatra? Either you made a mistake or I'm out of the loop when it comes to the JS world.

The only Sinatra I know of is http://www.sinatrarb.com/

The whole article is a little spurious. None of the languages mentioned (C, C++, D, Go, Rust) target exactly the same space (even though they all overlap).

Go and Rust in particular have been designed with very specific clients in mind (replacing Google's use of Python for server-side work and safety-paranoid multi-threading for Mozilla's Servo, respectively).

Rust is the only new language mentioned that resembles C in its capabilities but then again: C++ resembles C in (theoretical) capabilities but never de-throned C (mostly because when you use C++ like C, you might as well use C).

First and foremost: this is a good and fair post.

I disagree with Alexanders (regular) narrative that Rust puts a lot of estate into safe memory handling. Rusts memory management features may seem daunting at first, but they make advanced things (like type-system assisted data sharing) a breeze. So, while the whole "let's talk about data"-aspect of the language _does_ take a lot of estate, it goes far beyond "let's talk about memory".

I agree though that this is a property that comes rather late in learning the language and we still struggle to communicate that easily.

Wow, that's probably one of the last things I would have thought of. I look forward to listening to that.
I agree when Clojure gets rid of the JVM dependency. The Java ecosystem is nice but the annoying startup time of Clojure apps and the strange error messages of the Clojure compiler are reasons why Nim has become my favorite.
It would be more accurate to say C++ and not C. C is here to stay.

But the biggest question is not replacement but interoperability. Can I call Rust code from Go? Can I call Go from Rust?

All major open source C compilers are written in C++.

  >  Can I call Rust code from Go?
Yep. Rust code can easily expose a C ABI, so any language that can call into C (which is every language) can potentially call into Rust.

  > Can I call Go from Rust?
Go is working on exposing the ability to compile standalone libraries that can be called from other languages. Support was spotty last I looked, but it should be interesting to watch going forward.
Rust can expose C interface. If your lang can talk to C, it can talk to Rust
If Rust's syntax would be more close to other languages it would be the dealbreaker.

I mean most simple things are easy to read. But once in a while you stumble around code that nobody will understand if not every single character is well documented.

Still somehow I love it.

Nim for sure. Compiles to C and it's awesome.
The language known also as n_i_m and NiM?
I was involved in programming from the very beginning (the time of KIM-1) and I learned many programming languages, the major ones (C, C++, Java, Ada, Perl, Python, ...) and also very exotic ones (Assembler, APL, Fortran, Prolog, Lisp, ...). No language was more productive for me than Nim. Ever. It's the ideal "mix" of C, Python and Lisp with C++ native performance. Nim is really nice. I wonder why it is still barely known.

http://nim-lang.org

http://hookrace.net/blog/what-is-special-about-nim/

Uses Cases:

https://github.com/nim-lang/Nim/wiki/Nim-use-cases

Note that meanwhile there is also NimScript, an interpreter for a subset of Nim, which can be used for shell scripts.

Nim for scientific computing:

http://rnduja.github.io/2015/10/21/scientific-nim/

> The language known also as n_i_m and NiM?

http://blog.codinghorror.com/the-case-for-case-insensitivity...

I have no problem with that because this way everyone can use his favorite notation. The only thing that strongly reject are strong spaces. That was a silly idea and should be removed instantly.

What do you think about Julia?
I have barely touched Julia and I am impressed by the performance. It could become a real competitor to R.

Nim could also play a significant role because its syntax is similar to Python, and because NumPy is a Python API which is very prominent among scientists. However someone has yet to write a Nim library similar to NumPy.

Nim has the advantage of zero overhead to C, and it compiles to C which makes Nim an interesting option for super computing.

> Nim has the advantage of zero overhead to C,

Untrue. Nim requires the use of a garbage collector.

Replacing C? Not gonna happen anytime soon... I think C is a beautiful language and is probably one of the languages with more lines of code in the history, hugely used even today and the still the best for a good amount o scenarios.

Long live C!

From what I understand Cobol and Fortran still leads in number of lines. So much scientific software: weather simulations, military simulations is still in Fortran and Cobol runs at the core of so many banks. In my home country Norway you used to be able to download the code that was used to calculate your taxes (might still be possible but haven't tried in years). That code was all Cobol. So I suspect a lot of government stuff is also Cobol.

I am quite fond of C as well, but you know there are quite a lot of other nice languages out there as well. Since I started writing Swift, e.g. I haven't felt much need for C for anything anymore.

A problem for me jumping to C#, Java etc is that those are managed languages with very different set of tools and thinking. As a long time C/C++ developer, Swift feels much more natural as the tools, compile process and thinking is much more similar.

And Go has a very similar feel to C. When you read Go code it has much of the same simplicity and straightforwardness about it as C code. Even if I don't write much Go code I often read Go code to understand how things work, e.g. HTTP code, encryption stuff etc. Much easier to read the Go code than the C code or anything else really.

How does Swift do for embedded systems? Most of the processors in the world are not the usual PC, they are embedded systems. 99% of the embedded systems shop use C! There are still loads of 8 bits microcontrollers being sold every day and they aren't going anywhere anytime soon.

But I do agree with you, I am a web developer today and use Python, C doesn't fit too well in this space.

I've worked AVR microprocessors (used in Arduino) and I found that for as small programs as I would write on a micro controller even assembly programming works. But C is definitely a good fit. Since you need effortless access to many low level details I think C is probably the best language for writing micro controller software. Of course as the software gets larger I guess it start making more sense to switch to something like Swift or Rust.

The right tool for the job right? C is the right choice in many cases. It is just that C/C++ has been used for a lot more jobs than they are the right choice for.

If cobol is not dead then c will never die. Having said this I love writing in c, not because there are not better languages (there are), but because it provides a level of control that only assembly can beat. C is a very sharp knife.
> Given C++'s age, I'll assume in the following that the question also puts C++ alongside with C as a target for replacement.

Yes, C++ is old, but it has really stayed with the times in an impressive way. The so-called "Modern C++" that started with C++11 is a significantly different way of writing C++. All the things that made C++ infamously challenging and allowed inexperienced developers to leak memory and cause crashes, are, for the most part, no longer in the normal C++ workflow.

And all the rage about functional programming, passing around functions as values, writing closures that capture and encapsulate their surrounding values, using map, filter, reduce algorithms, relying on type inference, forgetting about pointer deletion and manual memory management and avoiding the access out of bounds memory on iterations -- that is all normal C++ now.

If anything has or will successfully replace C++, it is going to be C++ itself. The standards committee and community are doing an extraordinary job of keeping the language current while maintaining its great reputation for speed.

Yeah but the problem is that your benefits depend on the libraries you're using. You might not be able to use unique/shared_ptr because of some framework using different conventions internally.

But overall, I agree with you. C++11 seems different from when we used it in high school.

That's true to a certain extent. There are a ton of new libraries appearing though, and the benefits of moving to the newer features are so compelling that actively maintained libraries are swiftly moving over. In the past six months I've moved all of mine from C++03 to C++14 and going through the process of stripping out loads of Boost and internal facilities that are now in the language.
Smart pointers are about ownership. If "some framework is using different conventions internally" then that framework entirely owns the resource and access to it is not managed by smart pointers. That is a natural, fully idiomatic behaviour of modern C++ and is not related to any specific library.
yeah I am familiar with ownership from Obj-C reference counting.

But the problem is when your own code interacts with the framework that uses its own internal way of managing memory (ironically it's a copy of Obj-C reference counting)

Right now I've decided just to go with the frameworks way of doing things and inherit from their base object. The problem comes when I want to use this code outside in a different project :-/

Yes, I came to the conclusion that when one is allowed to use C++14 and specially with the upcoming GSL and lifetime analyzer, most of the warts are off.

For me, it is a good enough for when I step outside JVM/.NET work as I am an old C++ dog.

The problem is those that the only tool is the compiler and nothing else. On Herb's talk at CppCon only 1% of the audience confirmed that they use static analyzers.

Or those that have to deal with strict code guidelines or codebases that extend before C++98 as even a standard and don't even know what CppCon, HN or Reddit mean.

For those cases, I think only way forward are language that throw the unsafe cruft out and provide safe practices from the get go, without external tools that are optional to use.

I tried using new C++14 features, but the performance was terrible. Even compared to scripting languages. The problem is that you have to now performance profile every single feature and know all the gotchas.
Could you elaborate which C++14 features were slow?
I don't know his problems with C++14, but from what I encountered with C++ in general, there are some default settings that may affect performance, like the iostream syncronization with stdio, concurrency treatment in stl containers, etc.
I would have to find the exact example, but I tried counting words etc. Specifically, using the new built in abstractions is slower than not using the abstractions.

For example, unordered_map was pretty slow.

I just checked again though and it is much faster for counting words because they fixed a bug: http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg368041.h...

Edit: I know that example is a C++11 feature, but basically the idea is that you have to try things with different inputs before making conclusions.

Thanks for the example. I was thinking of language features, which are mostly cheap (type inference, move constructors, constexpr, initializer lists, range-based for loops).

But it may indeed be that some standard library extensions are not well-optimized yet.

That has nothing to do with C++14.

It was an gcc bug.

Remember that languages based on standards are not defined by what a specific compiler does.

So let's pretend we have a language ABC that is based on standards. It has one implementation and one standard library and the code can only be compiled with one compiler.

If the standard library's string functions are slow, can you not say that the language is not very fast at string manipulations? I am pretty sure most people would say that.

>If the standard library's string functions are slow, can you not say that the language is not very fast at string manipulations?

No, because it might still be an implementation issue.

One needs to understand why the string functions are slow, what is causing it.

Is the language semantic, the algorithm being used, the internal data representation,...?

> I am pretty sure most people would say that.

The ones without background in compiler design, surely yes.

Also the point of standards is exactly to avoid compiler driven development and foster competition between implementations thus leading to a better language eco-system.

C++11 in no way solves the fundamental problem of C++. C++ is too big and has too much baggage. There are too many corner cases and oddball stuff to deal with. Being a good C++ developer requires unnecessary amounts of training.

C++11 can't remove what is already there and so one just keeps piling on more stuff increasing the complexity.

I am actually sad C++11 happened because it keeps alive a language that should have died years ago.

I've worked years on projects where so many of the fundamental problems can be traced back to the usage of C++. Huge amount of legacy code which can't safely be refactored because C++ is just too complex a language for a refactoring tool to be able to deal with properly. Insane compile times. Odd hard to track down problems from static initialization and deinitialization. Templates are impossible to use in a sane way because they mix so poorly with regular OOP in C++ and increase compile times too much to be practical.

Move a project like that gradually away from C++ is a huge undertaking and nobody is going to support it as long as C++ keeps updating self to not be completely behind the times.

>There are too many corner cases and oddball stuff to deal with.

It seems like all the langauges I've used, from objective-c to swift and Clojure require you to keep certain aspects of the language in mind for certain situations that don't on the surface seem obvious. Purity in any language is quite rare.

In the case of C++, it is possible to ignore much of that old baggage most or maybe even all of the time if you write new code using new features. I agree that those maintaining much older codebases are going to have a rough time, but is not an uncommon problem in many languages.

Also, even in a so-called "better" language you can run into massive refactoring projects with older code once you choose to adopt new libraries and tools. As Bjarne says, C++11 is much better, C++14 will be even better, and C++17 is further going to be better... frankly, this is a good path for any language to be on.

There is much more weird stuff in c++ than in any other language. Especially rust.

Add to that that you also have to deal with the Makefile/Cmake garbage. Another solved by rust (rust is shipped with cargo which release you of the makefile hell).

I don't think purity is the problem. I just think simplicity has value. It makes it possible to keep most of a language in your head. It makes it possible for anybody on your team to have a chance of understanding your code.

There was a time I tried to embrace modern C++. Problem is C++ is so big that there will always be lots of people who don't understand the code you are writing. I used to have tech talks to explain concepts like C++ concepts, models and how it relates to STL containers, iterators etc. But ultimately all these efforts is just putting bandaid on a shitty language.

The whole point of programming languages is so people can exchange code and understand each others code. C++ is epic fail in this area.

While Objective-C is also a kind of old and crufty language, it is infinitely simpler than C++.

Maintaining old codebases in anything other than C++ is much simpler for many reasons. Refactoring tools in languages like Java and C# actually works. Refactoring in Ruby or Python is simpler because they more naturally decouple due to their dynamic typing.

Refactoring C++ code is hell on earth because the refactoring tool has to be able to understand macros, C++ templates etc. Any changes to a class interface even private methods or variables requires recompile of all files using that class. Which means doing lots of changes means recompile of lots of files. Which sucks in a large project when C++ is terribly slow at compilation to begin with.

Compare with a language like Go. The syntax is so much more sane that you can actually write simple refactoring tools yourself easily. No way in hell you can do that with C++.

No matter what Bjarne does with C++, they will still be stuck with macros, a fiendishly complicated template system, static initialization and deinitialization mess. As long as you need to remain backwards compatible you are stuck with a lot of awful stuff.

>But ultimately all these efforts is just putting bandaid on a shitty language.

Well, that's a highly subjective opinion. It sounds like C++ doesn't work for you but I still find it a fascinating and enjoyable language to work in. There are drawbacks with any language, and I guess the drawbacks you find for yourself in C++ are your business.

The main reason C++ is still in use is not the zillions lines of existing code. It's the lack of alternative. Other languages may excel in one or two areas, but if you consider the whole ecosystem, C++ is still the best. The availability of highest quality compilers for all possible architectures, build tools, IDEs, static analysis tools, profilers, libraries - all of these factors combined make C++ the first choice for many applications.

C++11/14 didn't just "happen." A lot of smart and highly paid people invested their time and expertise to make it happen. Were there a better alternative to C++, they would invest in that alternative rather than putting their time and effort into C++.

It's also great to see new ideas being borrowed from other languages and applied to C++. It shows that C++ is not a niche language some people like to view it.

I love to do C programming. C++ in comparison, I don't enjoy at all. I think it's the syntax. C# and VB.net are fun, and fast to work in. Obviously just my opinions of course. Java is fun and fast.

With C and even Objective-C, I have to plan everything out, and finely craft the code. It's meant to be closely examined and optimized and perfected. That's what makes it rock-solid in my experience.

I don't have type-related or buffer or memory related issues since its part of developing in the language. Things like Heartbleed are interesting, because obviously the guy was overworked and didn't spend enough time with the code before checking it in.

I view those types of issues as 'check-in irresponsibility' and it can occur with any language, not just C. My answer would be 'None of the above'.

If the next C standard were to introduce something like try/finally/throw to replace prehistoric libc-based setjmp/longjmp, it would shrink the gap between it and other languages, well, I'd say roughly by half.
It seems unlikely that would happen. What would be the semantics of stack unwinding? C doesn't have destructors, so (as with longjmp) you end up losing track of memory allocations which were pointed to by the stack.

I do offer my own pet wish for C though: Official support for __attribute__((cleanup)). GCC and CLANG support it.

The semantics would be nothing but executing the finally block. As a rule C programs do only what is explicitly coded. No high-level programming language behind the scenes stuff.
Different languages will probably replace different parts of C usage. I suspect Go will replace C/C++ for high performance server side stuff like databases and various server software. E.g. I've seen a bitcoin server being written in Go. That is the sort of stuff that makes sense for Go I think.

However C is often used for writing libraries that can be used for many languages. Think about OpenSSL e.g. I doubt C was chosen due to its credentials as a secure language. Rather this is a liability for C/C++ in many areas.

I think Rust will replace this. Actually I think Swift will be fighting with Rust over some of the the same territory. They both got the same advantage of not requiring a garbage collector and thus can be used to write libraries to be used by any language through a C-API.

While Rust might have an edge language wise, Swift might be just good enough. That matters because we are using C/C++ not so much due to the quality of those languages but due to a combination of their feature set and existing momentum.

Swift is more or less guaranteed to get big as it is replacing Objective-C for iOS development rapidly. That will create a large user base for it quickly. This will only accelerate when Swift goes open source and can be used on more platforms.

Both D and Rust have a bit of a chicken and egg problem. People aren't going to use those languages if people don't believe they have a future. They wont have a future if people don't believe they have a future. Rust is novel and cool enough in a geek perspective that I think it will gain enough momentum to get some presence. D has been around for a long time without that happening so there is no reason to believe it will happen now.

Swift has the chicken and egg problem solved. For writing something like OpenSSL it would take away many potential problems. No accidentally not executed code due to not using curly braces for if statements. No exploitable buffer or integer overflows. No accidentally uninitialized variables. No accidental switch-case fall through. No unintentional type conversions. A whole host of memory bugs gone.

On OSes written in C, C benefits from OS ABI == C ABI, but it wasn't always like that.
> Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery.

That could not have been more graphically enlightening.

I think that C is completely fine; Language is relatively simple, and so can be easily used/implemented anywhere. Any dynamic parts and GarbageCollection can be provided by C libraries.

By using source-to-source compilers, C is a good target language.

From this standpoint, we can treat C as a "cross-architecture assembly platform".

Simplicity is beautiful!

C is the assembly for the Unix virtual machine.
Yes, simplicity is beautiful but C is not state of the art anymore. In comparison to modern languages C is merely a high level assembler. Why fiddle with C when you can use modern languages which can compile to C anyway?
high level assembler - exactly!
No language will replace C, but all of those mentioned will eat some of its cake. Its usage will shrink, but C is here to stay.

D is what C++ should have been. It had some traction in mid-2000s but the Tango vs. Phobos debacle killed it.

Go is the most serious of the three languages mentioned. It has the momentum, solid community, solid tooling, and corporate backing. It's well suited for networked services, but it is not replacement for C.

I'm not so sure about Rust. Unlike D and Go, Rust can replace C (in theory), but I don't think that will happen. Rust has a feel of a hobbyist language in perpetual alpha.

> but the Tango vs. Phobos debacle killed it. It was D1 lang.

You should know now that D2 have single standard lib, the official compiler front end is wrote on D, and open source. Plus there is LDC and GDC implementations.

I know, but it missed an opportunity to go big.

In early 2000s, Microsoft basically told Win32 API developers to either migrate to .NET or to go fuck themselves. There was a lot of FUD flying around. At one point, people were wondering will the new Visual Studio ship with C/C++ compiler.

In it's quest to promote .NET, Microsoft even got Borland to kill itself by jumping on the .NET train. The days of native Windows development were over and the best alternative to MS stack, Borland with its Delphi, decided to commit suicide.

That was the chance for D to shine. I was among the developers looking for non-MS solution for native Windows development and D was my favorite, but the Tango vs. Phobos thing killed it for me.

Like many developers at that time, I left Windows for the Web development. If D was then what is now, I would stay with Windows a bit longer than I did.

  > Rust has a feel of a hobbyist language in perpetual alpha.
Would you mind elaborating on this? We released a stable version in May, so I'm wondering why it still feels that way.
I'll try.

First, I want to tell you that my comments are not malicious (at least, not on purpose), just telling you what impression I get when looking at it.

Rust got a lot of love from the beginning, a lot of people tried to use it before it was anywhere near stable. They've got burned when their two weeks old code wouldn't compile. I know, they were warned about it, but it still kinda sucks.

If you look at the Rust FAQ[1], it promises yet more incompleteness and breakage to come:

>4 Is any part of this thing production-ready?

>No. Feel free to play around, but don't expect completeness or stability yet. Expect incompleteness and breakage.

Another question people have is: "Are we web yet?" and the answer is: "No, we are not." [2]

No stability, immature ecosystem,... Either the docs are outdated or you're "selling" it wrong. The message I get is "Rust is awesome, but not here yet".

[1]https://doc.rust-lang.org/complement-project-faq.html#is-any...?

[2]http://arewewebyet.com/

  > my comments are not malicious 
No worries! I don't mind negative feedback, as long as its informed negative feedback. There's tons of bad stuff about Rust. Just like anything :)

Ah! That FAQ is straight-up incorrect, check the 'beta' link: https://doc.rust-lang.org/beta/complement-project-faq.html#i...

We released 1.0 stable in May. We don't make those kinds of changes anymore. The only reason that FAQ entry survived so long is that the FAQ is currently being entirely re-written, so people hadn't read it in a while...

"Are we web yet" is massively outdated. There's been PRs open for a year, with no response from the author https://github.com/teepee/arewewebyet/pulls

One advantage of D compared to the others is C++ integration. It can actually do it partially, whereas other languages just fall back to a C-ABI layer in between.
For me the minimalism of the Go language, the quick learning curve, the great standard library, and the ease of deployment make it a great choice. I hardly ever need to code things in low level assembly, but I do need to revisit old code frequently. The explicitness of Go makes it easy to work on coded you have not touched in 6 months. I have not looked at D, and Rust is still pretty new. I may give Rust a try in the future if I can find a project for it and I have some time to learn it.