Does anyone know what the move / copy semantics are in Carbon? I can't figure it out from the docs (admittedly I have not looked hard at all).
I would say the number one weakness of C++ is its model of copy by default and often by surprise. For example: f(std::move(x)) will copy x if x is const or f takes its value by const ref - rather than a compiler error as you might reasonably expect (if you don't know the C++ reference model inside out).
In Rust, moves are destructive (which simplifies implementions - you don't need an "empty" state) and always bitwise (which is usually fine, so long as they're destructive); and copies are always explicit so you don't have the above problem. I personally think that is all more useful than the borrow checker.
If Carbon has the same bizarre move/copy rules as C++ then the effort is wasted IMO.
> In Rust, moves are destructive (which simplifies implementions - you don't need an "empty" state) and always bitwise (which is usually fine, so long as they're destructive); and copies are always explicit so you don't have the above problem.
Rust has implicit copies too, e.g. if you do:
let v = 2u16;
foo(v);
then v is being copied. What Rust does not have is implicit deep copies. The auto-copying depends on the type and is only done for types that don't have a custom destructor, or to be more precise, implement the Copy trait. So a big array of integers gets copied (because it implements the Copy trait), but a Vec gets moved (because of its custom destructor there is no Copy trait implementation).
As Rust's documentation explains "... Under the hood, both a copy and a move can result in bits being copied in memory, although this is sometimes optimized away"
What's important about Copy is that, since you said you want to permit Copy here, it's OK if Rust keeps both identical bit patterns alive after the bits are copied. Just keeping both alive is obviously better for trivial types like u32, but on modern hardware it's also true for somewhat more complicated types like &str (which is a pointer and a count) or SocketAddrV6 (an IPv6 address, a port number, flow label and so on).
Thus, in your example, v is being bit copied (at least notionally) in both cases to become the parameter of this foo function, but because v is Copy, we can nevertheless use v again on the next line, the bits in v are still alive. If v was not Copy (e.g. an owned String) then foo(v) consumes v, it's moved into foo and now it's gone, we can't access v on the next line.
Sure, I knew about the Value trait but I thought it wasn't relevant for the general point (and I thought that sentence had too many parenthesised clarifications already!).
In Rust, types implement the Copy trait and the Drop (destructor) trait independently. Vec could easily implement Copy. It doesn't because copying a Vec requires an expensive heap allocation, which can surprise users when it happens implicitly.
No you can't, there is a specific error for that. You can try it:
struct Foo;
impl Copy for Foo {}
impl Drop for Foo {
fn drop(&mut self) {
// ...
}
}
It gives the error:
error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor
--> src/main.rs:3:1
|
3 | impl Copy for Foo {}
| ^^^^^^^^^^^^^^^^^^^^ `Copy` not allowed on types with destructors
> In Rust, moves are destructive (which simplifies implementions - you don't need an "empty" state) and always bitwise (which is usually fine, so long as they're destructive); and copies are always explicit so you don't have the above problem. I personally think that is all more useful than the borrow checker.
Without the borrow checker, this "move-by-default, move is memcpy" semantics would break all hell loose. Dangling pointers/references would be everywhere. I like this part of Rust, but I'm not sure if it can work in a non-GC, no-borrow-checker language.
You don't need a full-on borrow-checker to make move-by-default safe.
If you can track whether or not a variable has been (definitely) initialized, you can track whether or not a variable has been moved from. It's the same basic logic. And there are languages without full borrow checkers that can do that--Java is the first one that comes to mind.
Don't you need to know when all borrows end? E.g. here:
fn main() {
let x = [1, 2, 3];
println!("{:?}", x);
let y = x.map(|x| x % 2 == 0);
println!("{:?}", y);
}
x is borrowed by println (or rather by code that println expands to) and then it is moved by array::map. The compiler needs to know that before x.map(), x is not borrowed anymore. Otherwise it could be that println actually stored a reference to x somewhere and now you have a dangling reference possibly breaking type-safety (referring to an array of bools through a reference to array of ints, if the map is implemented as an in-place operation).
I see that destructive moves would in theory introduce more opportunities for that, but I don't really see it making a big difference in practice - routines that take a pointer/reference and hold onto them (without taking ownership) already need a lot of care in C++.
You would need to add the rule that you can't move from a variable in only one branch of an if statement or from any sort of loop. Like a really primitive compile time borrow checker.
It seems to me that would be enough, but maybe I haven't thought it through properly, or maybe you'd end up having to copy a lot more often than you want to (or use optional half the time, which might defeat the point a bit).
> Does anyone know what the move / copy semantics are in Carbon? I can't figure it out from the docs (admittedly I have not looked hard at all).
I read the documentation and had the very same question. My notes from the announcement thread had this line in it:
> * Not clear from the main design document is how the distinction--if any--between trivial/nontrivial copy/move types work. There appears to be an explicit move operator (with obvious syntax ~x), so support for nontrivial move or immovable is better than Rust already, but the avoidance of a NRVO setup still makes me wonder what the actual story is here.
Given that Carbon copies the signed-no-overflow/unsigned-may-overflow distinction from C/C++, it wouldn't surprise me if they also copy the move/copy rules from C++, as those are both rather fundamentally baked into C++ (which means you have to deal with it for automatic translation), even if they are pretty objectively confusing.
I agree that it should have been named better (rvalue_cast might have worked) but that wouldn't have solved the core problem: Does f(std::become_rvalue_reference(x)) make a copy of x? It's more obvious that it might but I still lack the facility to make it cause a compile time error if it would (except changing x's class to disallow any copies at all).
In general you can't answer these questions by reading the call site. You have no idea what kinds of intermediate functions are implied by f(x). Maybe f() doesn't take an X at all, maybe it takes a Y and there's an implicit Y::Y(const X&) hanging around, or perhaps there is an X::operator Y(). You can only understand f(x) by reading the definitions of f, its argument type, and X.
The Foo& case won't compile. Const foo& will as temporaries can bind to const references; this is desirable and x is still moved from.
The plain Foo case won't do any copies because of NRVO and temporary elision (both optimizations are now guaranteed by the standard); again x will be moved from.
The upside of this implementation is that x is always moved from. The downside is that sometimes more objects are created (for example in the const&) than the pure cast case and can't always be reliably optimized out.
> The Foo& case won't compile. Const foo& will [compile]
Not true. Both Foo& [1] and const Foo& [2] parameter types fail to compile (in gcc 8.5, I also tried gcc 10 with same result).
Bizarrely, in more modern compilers, including gcc 11, both Foo& [3] and const Foo& [4] do compile, even with the language version forced to C++11. I'm very curious to know why; presumably there's some defect report that got retroactively applied to all standards, but I can't find anything relevant. In any case, this illustrates how cryptic the C++ rvalue rules are.
> Const foo& will as temporaries can bind to const references; this is desirable and x is still moved from.
Well that (it's desirable) is your opinion! In my view, in an ideal world, f(move(x)) would not mean there is at least one move... it would mean there are at most zero copies.
I forgot remove reference for the T in the result type and in the return statement.
Interestingly it compiles with gcc-12 for some reason.
In generic code you do want to copy if T is not movable (for example when implementing a container). The annoying thing with the existing std move is that it might or might not move from the x depending on the implementation of the sink. This implementation will always move from if x is movable.
Different tradeoffs.
Now can we make a move with your requirements (only move no copy?) I think so. Let me think about it.
I'm probably just biased, but to me the problem with modern C++ is its complexity. The mental model of the language, its syntax, and the amount of history / number of interfaces a programmer needs to be familiar with to be productive are all too large. Rust isn't any more complex, but it's not radically simpler either. Carbon doesn't look like it solves this problem. It would seem that creating a language that is expressive, performant, and small while still general purpose is quite a challenge.
In general, I think it's easy to conflate simplicity with ease. Ease is always a matter of context and what one is familiar with.
I agree that Rust is simpler than C++ and I think a lot of people mean that Rust isn't easier (up front). Given how new and different it can be, that makes sense.
Rust's slogan is: "A language empowering everyone to build reliable and efficient software."
Now, that "everyone" there has a bunch of social consequences, like you're going to see a bunch more diversity in Rust's community than we've traditionally seen in this sort of endeavour. But it also means technically there's work put in to actually deliver on the slogan by making it easier for everyone to use the language.
This is how Rust has those excellent compiler diagnostics. That's not an accident, it's part of "empowering everyone". Experts could manage with a compiler that outputs terse errors like "Syntax error, line 14" but that's not going to empower everyone.
Yes, but C++ isn’t complex because it set out to be complex, it’s complex because they’re constantly trying to enhance it whilst maintaining backwards compatibility with a system that was originally basically just a big set of CPP macros.
Rust has a heck of a lot of features, but it’s got nothing like the “too perfect forwarding” problem of the language behaviour just being plain hard to predict.
The idea of classes on their own isn't complicated. The problem is that C++ provides an extreme amount of flexibility in how you use them.
You can have multiple inheritance. You can have as many levels of partially implemented, partially abstract classes as you like provided you eventually have a concrete class, and these abstract classes can have member data. You can have static methods, which I've seen abused as namespaces so often. You can have static methods and non static ones in a class hierarchy. Finally you can mix templates into this.
In an ideal world the developers of a project in a company would collaborate to keep this from getting out of control and enforce a relatively consistent philosophy. However in practice people have their quirks and specific not always rational views, and programmers are in general not always the best at dealing with other people, programmers included.
So a strong personality is determined to do it one way and refactors a bunch of code to their liking, and on and on, and now a variety of features have been used in different ways.
No language is immune to this as it is fundamentally a human problem, but taking out features generally helps. Since we can get by without inheritance most of the newer languages have done away with it.
It is difficult to tell sometimes due to its religious backward compatibility, but C++ has been becoming significantly less complex over time. I have a large C++ code base (originally hundreds of thousands LoC) that I aggressively modernize, essentially rewriting it idiomatically in new versions of C++. It was originally written in C++0x/C++11, rewritten in C++17, and is currently being rewritten in C++20. You can barely tell the code bases are related beyond being functionally similar.
It is also important to separate C++ the language from its standard library.
As C++ the language has modernized, it has dramatically reduced the lines of code to express a given thing. And the more modern way of expressing the thing has stronger type safety, more flexibility, and better composability. Things that used to require a lot of template metaprogramming magic to pull off are now clean one-liners. Particularly in C++20, which is probably the biggest step-change since C++11, metaprogramming is simultaneously much more powerful and much more readable. A lot of code that used to be written is now metaprogrammed. Previous use cases that required C macros largely have native C++ equivalents at this point.
The major issue that makes C++ seem complex is the standard library, which was largely designed and written for legacy versions of C++. If you use the standard library heavily, it tends to want to be used in the style of C++ for which it was originally written. If you built a standard library for C++20 from first principles, it would look quite different from the one we have. Hence the proliferation of non-standard "standard" libraries for C++.
> You can barely tell the code bases are related beyond being functionally similar.
Not sure if you've missed this, but this is a number one reason many consider C++ absurdly complex. To actually know C++ is to know many different similar languages based on the year the code was written. C++20 is very different than C++03 as noted. Now compare this with C, or Go, Java, etc. which in comparison have barely changed.
I'm not sure your code is simplified either because of the modern features of C++ or because of the rewrite.
That said, I like the idea of rewriting old C++ code with modern C++. That'd be also a good way to learn modern C++ in a practical way and having legacy code serves well for this context ;-)
A language in the niche of C++ is always going to be complex (see rust), although possibly not as complex as C++.
I think that Carbon is not meant to be 100% backward compatible at least at this point, so they can iteratively try to smooth the rough edges of the language.
This seems to be a very hard idea to convey to people. Zig is on the opposite extreme-- the mantra being "There must only be one way to do something". Ergonomics and simplicity seem to be overlooked aspects of programming language design
That's great if there is one developer working on each component of the software. The moment you have people trying to do cross-component changes, or developing someone else's component, they don't just have to learn how the code works on a domain level, but also the features of the language the code is using.
The more recent editions of C++ do seem to support this idea. Things are at least better than when the trade off was taking advantage of C++ features (and more C++ like) or performance (and more C-like C++). The problem that there are only a handful of people who could realistically claim to be experts in C++ has gotten worse over time as the language has expanded though. It's a language where you potentially have to train new C++ programmers that join your team in how your team uses C++.
Well upto certain limits versatility is important. But, being too versatile also brings more complexity and it makes language confusing. I read more code than I write, so this versatily is not good for people like me.
Isn't the 'kitchen sink' approach what ended up causing Perl to fade from relevance? I am only casually aware of this, and I may be totally misremembering things, but Perl used to be seen as a swiss army chainsaw but people eventually came to realize that maintenance was a nightmare.
Perl faded away because there was an alternative (Python) and it was not a kitchen sink. For C++, there's no alternative at all. People have to bear with it.
It's not inheriting the complexity though. That's sort of the whole goal - the next 'generation' of C++ that can be used interchangeably with actual C++ but allowing re-visiting most of the design decisions and throwing out old features.
The Github Page[1] says this: "The best way to address these problems is to avoid inheriting the legacy of C or C++ directly, and instead start with solid language foundations like modern generics system, modular code organization, and consistent, simple syntax."
Seven years ago someone at Google estimated that there was 2 Billion lines of code in production to support Google Services [1]. Given this was seven years ago the number is probably much higher now and a large chunk of it is C++. Clearly any replacement language for C++ has to seamlessly (as primary design goal at least) consume and update this gigantic C++ code base. Nobody is rewriting all of that from scratch. That pretty much rules out Rust, Golang and various other languages which provide a thin "extern C function" level compatibility at best. Would be interesting to see how the language progresses.
Exactly, Rust has been around for a while and it hasn't reached parity in terms of LoC with C and C++ in Gecko's codebase, presumably because it's impossible to rewrite individual units unless the API is impossibly narrow. This new language will be more like different JVM langs in terms of interop.
The "slow" isn't the performance of the application, but rather the ability to make changes to the language.
As it is, Google can't make changes to C++ that it wants in a timely manner (if at all). Having a C++g edition where there are slight changes to the language for the Google flavor rather than the latest standard makes things even worse.
From Google's perspective, the same can be said of Rust.
What Google does see is Swift where there are significant evolutionary changes to the language over the time.
So, Google has created their own language to fit into a similar space as C++ and allows them to make changes to the language at a much more rapid pace than the C++ standards committee would have.
My crystal ball says "this language will diverge further and further from where it started as Google changes it to solve Google Problems."
This shouldn't be a "Oh! Neat! Everyone start coding in Carbon - it's the next C++!" Yes, it's interesting in that there are some interesting ideas in it and refinement of ideas that aren't practical elsewhere. However, this is a language created to solve Google's problems - not the world's.
Rather than enforcing the style guide ( https://google.github.io/styleguide/cppguide.html ) through code reviews and code review tools, the language itself encourages the developer to write better code than they would have if writing C++.
The Google C++ style guide is longer than the Carbon language design (though I will note a large number of sections that are "TODO").
(working from guesswork here)
Given the codebase that Google currently has in C++, the amount of effort to continue enforcing those style guides through human "this needs to change before I can approve it" to (in Google's eyes) more reasonable code with Carbon ultimately results in less developer time being spent reviewing style guide issues. At that scale, this may become a significant savings even when taking into account creating a new language.
While I intend to learn more Rust, compatibility with existing code is a big reason why I'm paying attention to Zig. It's not yet 1.0 and it's closer to C than C++.
However, because it's meant to compile and interop with both C and C++, I'm hopeful that it'll be an easier switch for more projects. It doesn't provide the safety checks that safe Rust does, but safe Rust requires a rewrite IIUC.
I haven't used Rust much, but based on everything I've read it seems like if you need a better alternative to C or C++...Rust is pretty much the answer. Is that not accurate?
This comment and parent comment don't appear to have read the article. It's specifically targetting C++ compatibility, that means compatible threading model, memory model, ABI, type system, ...
Rust has none of these. For every line of Rust code in the world, there are likely 10e3 - 100e3 lines of C++. You can either label it all "legacy code" and pretend your employer has the budget or time to rewrite it all, or you can find something in between writing new "legacy code", or throwing away your (for a company like Google) absolutely huge investment.
FWIW projects that build for interoperability have a much higher chance of long term success than those that don't. This is true for everything in software, not just programming languages. For this reason alone you can't easily compare Carbon and Rust. Carbon sounds something a little closer to Vala (C compatibility) than anything like Rust
Google rewrites a lot of their software components from scratch every few years, at least according to section 2.11 of this paper: https://arxiv.org/pdf/1702.01715.pdf
I only run one team, but this is not my experience at Google whatsoever. Some stuff gets rewritten but this is not planned and is largely due to catastrophic changes in requirements or very bad initial designs.
If they manage to make Carbon highly compatible with C++ (which is one of the design goals IIUC), then a C++/Rust compatibility layer should work fine with Carbon/Rust, or am I missing something?
That's a big "if" of course, and time will tell whether they manage to pull it off, but at least that seems to be where they want to go.
The same approach to compatibility with C++? Can you use Rust as successor language in a C++ codebase, just like Typescript in a Javascript codebase? From my (limited) understanding that's not as straightforward, and other sources online seem to agree with this (e.g. see comments in
https://old.reddit.com/r/rust/comments/w2tygg/carbon_languag...).
The way I see it, Carbon has C++ compatibility as a requirement, adding as much safety, performance etc. as possible on top, while Rust seems to start from a safe-by-default approach and building its way from there.
From experience binding some Rust and C++ is not a trivial task. The introduction of Rust ownership and lifetimes alone means this always involves new design, even just to provide something approaching a 1:1 mapping to an existing API. True 1:1 mappings at least in my experience simply aren't possible, there is always some contortion required to reduce the freedom+unsafety exported by C
> if you need a better alternative to C or C++...Rust is pretty much the answer. Is that not accurate?
If the thing(s) that you're looking to "better" about C++ are its atrocious compile times and/or the C++ culture's even more atrocious shared aesthetics, then the answer is "no".
I have only dabbled in Rust but I found the interop situation to be less than ideal. Plenty of C/C++ libraries either don't have Rust wrappers at all or have been long abandoned.
I like the ability of Carbon to seamlessly integrate with existing C/C++ code and libraries.
We have more than 5 C++-alike languages that are crawling around already. In some ways they have portions of mutual compatibility. But in practice this only matters if you decide to embrace the complexity of five different programming languages when building your software. It's already somewhat challenging for projects to manage assembly, C, and C++.
assembly, C, and C++ is one of the most "standard" things to do out there. Unless you are talking about non-standard toolchains of course (everything that isn't clang or gcc based). C++ is mostly a superset of C so all the C++ compilers out there have pure C modes, and assembly integrates really well into C and C++ build systems.
knowing neither of these languages i’d rather it be labeled something more clear as neither one of those screams immutable to me. the immutable variant should use the ‘const’ keyword instead.
Well Nim also has `const` the difference is that `const` must be evaluated in compile time, but `let` is just to prevent reassignments, more info: https://nim-lang.org/docs/tut1.html#constants which is different than what JavaScript does.
3 people now saying the same thing. const is not required to be interpreted at compile time, these are choices made by language designers. and read the code with ‘let’ in it like it’s english, does let actually describe constnenss using its english definition? no. i’d argue that any language using ‘let’ for const values is borderline too theoretical. hell, even “define” is better than “let”
I admittedly only have moderate experience in Scala, which uses `var`/`val` -- but I am glad Rust opted for `let`/`let mut` instead of a single word to make the distinction. It feels much easier to distinguish between mutable and immutable values.
I wonder if `var`/`let` is easier because the words aren't as close as `var`/`val`? Or maybe it just gets easier with experience?
I'm jumping into this a few hours late, but nobody has actually straight up asked the real question: Why try to compete with Rust while not really being a better Rust? The linked article generally defines a language that is more of the same, while Google is throwing Go under the bus to make it happen.
The number of current and former Google employees that transitioned from being Gophers to being Rustaceans that I know of is basically a 100% conversion rate. Nobody at Google will use Carbon, nobody outside of Google will use Carbon.
> Why try to compete with Rust while not really being a better Rust?
The linked article explains this: classes defined in C++ can be used in Carbon and vice-versa. It even suggests you stick to Rust if that's not what you need.
Edit: Oops, I assumed that the "linked article" was the github page[1] for Carbon, which is a lot more useful.
I guess the README really does answer my question: "Existing modern languages already provide an excellent developer experience: Go, Swift, Kotlin, Rust, and many more. Developers that can use one of these existing languages should."
My read on Carbon is that Google is in a spot where they have enormous amounts of C++ code flying around in a very idiosyncratic C++ dialect, and standard C++ is not working that well for them. So they are looking to create a C++-compatible language that better serves the needs of their codebase. We've seen this before with Facebook and PHP.
What's wrong with Swift? It's a replacement for Objective-C, that nobody besides macOS/iOS devs used anyway, therefore it's no big deal if nobody uses it outside of macOS/iOS development, as it's not a regression
Very few people are using it at all, outside of calling OSX/iOS APIs. They're using it to weld platform support into a C++ codebase, same way they'd use ObjC for that (instead of writing entire apps in it).
The number of pure-Swift projects I've seen per tempus is far less than pure-ObjC, which I think is the best measurement to comprehend Swift uptake. Nobody wanted an ObjC replacement, Apple misread the room.
This is a horribly misguided take. According to the latest S/O Developer Survey [1], Swift is used by 4.91% of respondents, while Objective-C is only used by 2.39%. Additionally, Swift is loved, and wanted by 62.88% and 4.3% of respondents, respectively. Objective-C is no where close by comparison...
This might be difficult to communicate, but I feel like XCode has me spending way more time and clicks on window/pane management than other IDEs. Apple's design philosophy is to keep things minimalist and hide controls which are not in active use. This means I find myself going back to click on small buttons in order to bring up a pane that will finally allow me to just to click on one icon I need to perform some task. Whereas in other IDEs can I force an icon to stay visible and spend much less time traversing the application's UI.
For an analogy, imagine using a workbench and being forced to put each tool back into it's respective drawer once I am done using it - even though I will certainly need to use the tool again very soon. Whereas other IDEs let my workbench be as customized and cluttered as I want it to be.
The only people I've seen claim Xcode is great have never used virtually any other modern IDE, which basically all run on your hardware/OS of choice.
But the IDE isn't the worst of it, the command line tooling is woeful.
That the same company could come up with a great language but provide so little incentive for anyone to use it baffles me.
I spent half of my iOS experience of a decade in ObjC and the last half in Swift. I also used ObjC way back when it was in NeXT. No comparison, you'd have to have your head examined to start something in ObjC today. The only reason to do it is maintain an old codebase; in my last job we replaced a huge ObjC codebase (written before I got there) entirely in Swift with higher quality and no issues (reason why was not just to convert it, it was part of a large new invasive project that was canceled but we shipped the Swift rewrite anyway).
I'm not sure that's a great take. Swift's support for Linux is reputed to be bad (not sure what the actual case is) and I think that really hinders adoption. It's a nice language that is very expressive. I would use it for small projects over rust as it has a large standard library if not for the cross-platform difficulties.
It became a kitchen sink language similarly to C++. For all the hate Java gets, they did tackle language development very well - wait a bit for other, niche languages to be your testing ground of new features, and only add what sticks. Swift literally has all the features you can find in today’s modern languages, and they have some inconsistent interactions with each other. Also, even this litany of features isn’t enough to make SwiftUI implementable only as a Swift library, it uses some specifics not available in the language otherwise.
And also, as most apple dev tools, it is the only modern language whose compiler failed under me (other than being slow as hell) - I have never gotten a type inference timed out error in other languages, even though it has been around for a time :D
As for growing a language, this is a must watch (bear with the presenter for the bit, you will soon understand why he talks strangely in the beginning): https://m.youtube.com/watch?v=_ahvzDzKdB0
Golang and C++ don't serve the same purpose. Google internally sometimes uses both to the same effect but that's because Google internally has a bunch of stuff (including new kernel syscalls) that makes highly concurrent server development in C++ palatable.
So why "compete" with Rust? Because C++ compatibility was never a design goal of Rust, so gradual, painless migration from C++ to Rust is a non-starter. The best you can hope to do is rewrite entire subsystems where the API is narrow enough. This new language is obviously going to allow something more like Kotlin or even Swift where codebases will be mixed and new code will be written in Carbon.
Google is contributing to "gradual migration from C++ to Rust" via autocxx and crubit. This Carbon thing looks more like a side project, and is still quite incomplete in many ways.
Crubit and autocxx have, afaict, less investment than Carbon, and all three are collaborative. There's not certainty that crubit or autocxx will succeed. If they do, awesome. If they can't, Carbon exists. All three are experimental all three are incomplete in many ways. None are side projects.
I don't really get it either. The article says they want to focus on being a more direct replacement for C++ with easier conversions. I don't see that though - take maybe the most important issue, memory safety. As far as I can tell, they either 1. Take the C++ approach of mostly-manual with lots of inevitable mistakes that result, easy conversion, or 2. Rust approach of strict ownership and borrower checker model, which will almost certainly require substantial reworking, just like if they had used actual Rust, or 3. Golang approach, give up and go GC, in which case they won't touch the performance, low level features, and memory footprint of C++.
So which way is this gonna go? Or do they have some other way to do memory management that nobody's thought of yet? If they had that, it'd be much more impressive than anything else they've said so far.
Because Rust is equally a terrible language to work with unless you're aligned with the objectives of the languages.
Go is a bigger language than Rust, it's not surprising to see people move over, that doesn't mean it's going to get used.
You're also vastly underestimating the number of people who otherwise like C++ and wish there was just an easier to use version.
For example - if 'Magic Carbon' somehow got rid of the ugly parts of C++, integrated smart pointers into the syntax, made the tooling, builds more robust, and somehow made it possible to integrate with C/C++, it'd be my new favourite language.
Rust has complicated interop with C++ and it is incredibly difficult to automate useful transcompilation from C++ to Rust. Various dynamic safety tools also don't work when you've got both Rust and C++ working together. The idea with Carbon appears to be a language with a much easier ramp for existing massive C++ codebases.
> Rust has complicated interop with C++ and it is incredibly difficult to automate useful transcompilation from C++ to Rust.
The problem with Rust is that it does not have this built directly into the language and relies on third party libraries. That doesn't really scale properly and some of the solutions are half-automated and needs lots of fine tuning, flag toggles and other configuration for it to work.
Carbon, Swift and D have a different approach in integrating the interop capability directly into the language which does sound like an easier way to automate this use it for existing C++ libraries. But I guess that this approach is not easy, but it seems with D lang, it paid off.
To be pedantic, it already isn't; a small but very important part of Linux is written in assembly (it used to be more, but most of it was ported to C; what's left is a small core which simply cannot be expressed correctly in C).
Still a maybe, and they certainly won't be rewriting any core part of the linux in Rust.
While the memory safety aspects of Rust is good for security, its still an evolving language and doesn't have the same stability as C. Its the same reason why C++ hasn't been adopted.
> Its the same reason why C++ hasn't been adopted.
Among the reasons C++ hasn't been adopted for Linux:
* Nobody actually did the hard work. The Rust for Linux people have spent a lot of time actually making this possible. C++ proponents tend to just drive past "Ha, you should use C++" which they presumably think makes them seem clever but it doesn't.
* C++ doesn't have a coherent "freestanding" subset. In theory (and according to the ISO document) there's freestanding C++ but in practice you quickly find you need lots of custom runtime stuff, it's not really part of the C++ standard at all.
* Linus is trying not to be an asshole and that's not going to be helped by introducing a C++ culture where you'll routinely see sentiments like "This has a Code of Conduct so it's for fucking snowflakes".
* C++ loves implicit allocation and Linus hates implicit allocation, especially infallible allocation. Now, you could sort of fix this if you rewrote a lot of stuff, and indeed in the Rust for Linux implementation of alloc (Rust's allocation library) there are a lot of places where it does fallible allocation and doesn't offer implicit allocation.
The example of the latter which won't affect most kernel programmers but I think is easiest for a typical programmer to understand is this: In C++ or Rust, if I have a string called adjective (maybe it's "Fast") and a string called noun (maybe "Cheese", and I write phrase = adjective + noun; then we're going to get the resulting word from concatenating the two strings ("FastCheese"), right? Is this abuse of the + operator? Maybe. But it works. In Rust for Linux that won't compile. Because it's an implied, infallible allocation. To put that concatenated string somewhere there's an allocation, which could fail, and how could the + operator "fail" ? Where does the error go if this happens?
Speaking not from direct experience, having barely touched C++ in the past and never touched D yet, but I've read many paint it as the natural successor, so why not D?
Yeah I don't really understand that either. I have never written D myself but everyone I've looked at the language it has seemed to have sensible solutions to things and I would much rather write that than C++.
I guess it hasn't as good interoperability with existing C++ as Carbon is aiming for (I don't think, could be wrong) and wouldn't give Google as much control of it as it probably will have over Carbon.
Is D safe like Rust? I don't believe it is. I've written a little D and I like it but we need safe languages. The industry ignored the safety of Pascal, Modula-2, and Ada back in the 1970's and chose C because it was slightly faster. Now we're getting hacked left, right and center and have a huge base of C and C++. Sigh.
While I have not had time to check this out, more generally whenever I read “Google launches…” I wonder how long until it makes it into the ever-growing graveyard?
This is an experimental project, being very clearly pitched as such, and with the documentation being really clear about how if you can use any other language you should. They're bending over backwards to make the expectations clear. It is being developed in the open, targets a goverance model of an open foundation not controlled by any company, and has a goal that no more than half the contributors to the language should be from any one company. It's also a programming language whose compiler you'd run on your local machine, not a networked service that can actually be shut down.
Out of all the projects where you could trot out this tired "killed by google" shit, this is literally the worst one. What is your thought process here? "I don't know anything about the subject, but let me repeat a lame joke that people will surely find hilarious despite it being the thousandth time it gets posted to HN this year. Surely it will play to the crowd."
No, those are two separate things which is why I listed them separately. There is the question of the governance / ownership model is (independent foundation), and the question of having a broad base of contributors to the design / implementation.
What, exactly, would they need to do to satisfy you?
It’s clear that the value promise of Carbon is to make it attractive to port existing C++ applications to it.
But how this is accomplished, article does not go into detail in this. Is there going to be ABI compatibility with C++? What are the features that make Carbon a better porting target than Rust?
The official webisite (https://github.com/carbon-language/carbon-lang) goes into better detail, but the gist is that you can basically #include C++ libraries and use their APIs as-is, without needing to resort to unsafe blocks or having to write more idiomatic wrappers.
There is ABI compatibility insofar that Carbon will be able to integrate C++ at the AST level within the compiler.
This is quite smart as you are basically getting ABI compatibility for free. Assuming you have the source code to the C++.
I'm not sure how it will work with dynamic or proprietary libraries, but as I understand it that is already a technically unsolved ABI problem with C++.
Rust will require a complete re-write or extensive work implementing a C-like interface for your C++ API. Carbon will be able to use C++ classes natively, including calling methods etc.
I think Carbon will be a much better choice for extending a C++ project.
Rust might be a good choice if you are able to start from scratch or the project has C bindings.
Rust is closer to the the type of languages we need to move to but Carbon makes it easier to port away from existing C++ software. If it's a new project, use Rust if you can. Use Carbon if you need to deal with C++. Rust can interoperate with C++ but with more difficulty.
Major upgrades that are fully backward compatible and therefore leave some significant performance and safety bugs untouched. What they mean by "slow evolution" is the increasing rigidity of core data structures and resistance to introducing replacements caused by the backwards compatibility promise. Adding new features is easier than changing existing ones.
This is both a strength and a weakness of C++. It's a very old language and it has been keeping that backwards compatibility promise for a very long time. The result is that certain portions of the language are effectively unchangeable as a result. This is the key thing that Rust's editions are trying avoid.
There are new versions and C++ has had a lot more love recently than in the past, but a lot of valuable changes are made impossible by the committee because of compatibility concerns.
Depending on what abc is (variable or type name) it can be either a multiplication or pointer variable declaration. With the new syntax ambiguity is reduced.
This might not be a huge issue for people reading code (because in context it should be pretty obvious), but for compiler it means that type information is required to parse code and compiler stages get mixed together.
I can't see details of the Carbon syntax for pointer, array and function types, but this is where Rust's type syntax really excels compared to the C++ style.
let foo : & fn(&[MyType], i32) -> String = ...
(a reference to a function that takes a slice and a 32bit signed integer as arguments and returns a string)
is dramatically simpler than the C/C++ equivalent.
More subjectively, I find `var` or equivalent makes code much easier to read, because you can scan for variable declarations much more easily. With C++ code, almost any token could be a variable declaration and you have to think about the type even if you wouldn't otherwise care about it. It also allows you to have inferred types without a separate auto keyword.
Well the syntax for declaring a function in Rust is:
fn foo_bar(foo: &[MyType], bar: i32) -> String { ... }
so probably to match that.
I believe Haskell does something clever such that there is no difference between a function that takes two parameters, and a function that takes one parameter and returns a function that takes the second parameter. This isn't the case in Rust. Those would be distinct types and the latter would be called differently to the former. So I'm not sure that the Haskell syntax would work for Rust.
I really disagree. Specifically when you have types nested within one another the complexity doesn't increase much. Whereas with C++ style declaration it quickly becomes type soup.
I think by using `var` keyword you have the potential to inherit the type without changing too much the syntax, in rust you could omit the type if the compiler can inherit the type, that saves you a lot of typing in the future, but you could argue that it makes harder to read the source code without any tool.
Ask a non programmer what each means or measure the time newer devs take to understand it. On its own maybe its easier but I suspect for people its the same or saying var is easier.
Its 5 extra characters actually.. because any sensible C++ project has i32 etc defined.
The type omission version isn't very useful, as this type of code is difficult to read later. Generally end up regretting using auto, and end up converting it to the actual type, except with iterators or nasty templates.
The example to me looks like C++ is still nicer, I don't get the hate on C++ but then again most of the native work I do is gamedev.
The benefit that C++ and Carbon can run together is a nice feature. It is like Objective-C++ (using ObjC + C++ together) or Swift/ObjC that worked well in gamedev as well when you needed to wire in a C/C++ game engine into iOS. For Android the NDK.
I think any C++ replacement has to be compatible with C++ but at that point isn't C++ still the root? C++ will never go away and it is actually a great language that is powerful. Then again I have spent lots of time in gamedev where that matters and most libs are going to be C/C++ for the foreseeable future.
Just learn C++.
You'll probably need to learn C++ to understand integrations with Carbon anyways. Carbon seems like yet another language you'll have to learn that is built on and tries to replace C++.
Fun fact: Fun fact: Objective-C was made in 1984, one year before C++ (1985).
I work on a project that is a c & c++ codebase where there isn't really a great reason for it being in those languages vs a language "with a runtime"
the hate is pretty simple:
- compile times
- vague compiler errors
- template syntax is incredibly hard to read, especially when using techniques like sfinae, or trying to write functional interfaces
- really bad names for idioms (raii, sfinae, pimpl)
- really bad names for standard library types & functions
- truly arrogant community (notice how the boost website doesn't advertise that it's the easiest to use library -- it's the "most expertly designed")
- class member function declaration is out of control (`virtual const foo bar(const baz& x) const override`)
- defaults are unsafe (mutable by default)
- package management is a nightmare (i've only used conan, which is starting to mature, but still has a limited selection of packages, and seems to
constantly break how they do things...because package building for an ecosystem as wide and unstructured as c++ is an intractable problem)
- cmake is the worst dsl ever. the program itself is fine, but the dsl is the worst.
- footguns everywhere (auto vs auto&...but auto* exists, and isn't necessary)
- N different ways of initializing
- it's incredibly hard to teach
- inconsistencies w/ C (brace initialization w/ named fields)
- incredibly subtle things can have a huge impact (class member variable declaration order)
- no standard way to document classes & functions
there are still certainly use cases where it's worth using, but the hate is pretty straightforward to me: it's just more hassle than it's worth most of the time. and there is some inner language struggling to get out that's probably nice to use. There are some nice things about it: notably static destruction.
and yes, some of those are more ecosystem based / my own opinions / not necessarily "the language" -- and there are reasons for why many of the warts are the way they are (backwards compatibility, control over construction order). it's still a giant pain in my ass.
Many of these things are indeed true problems. But they miss the big one: C++ is just plain unsafe. Applications written in C++ that process untrusted input are serious security risks. The industry needs a path a future where no C++ code is processing untrusted input. Rust is (mostly) safe, but the path to shift gazillions of lines of C++ to safe Rust is painful.
Good points though many platforms/languages have similar issues, just C++ has been around longer and has been used the most. C++ has always been a sort of peak language and probably always will be because like C, or machine code directly, everything else is built on it: virtual machines, apps, compilers, platforms etc at the root.
C++ is one of those things that when you grok it and can ship with it, everything else is easier. The years I have spent on C++ I have enjoyed because everything else looks easier and how performant it is. It is fun to code in as well. There are many ways to do things in C++ and that is a feature. I also feel like people use less dependencies and do more custom code in it but that may just be a gamedev thing. I like that style over using thousands of dependencies and less ability to control memory. While maybe it can be unsafe if done incorrectly, it surely has less attack vectors at the dependency level like other software today.
Additionally, it seems like C++ is still a language where programmers/developers control the products over all the middle layers that control modern software, like the hellscape that is project management of software today.
Like everything from Google I'm too worried that it will be deprecated or evolution to be incompatible with previous versions to touch it. Google might have the human power to rewrite their codebase every 6 months... But I don't. I need something stable.
Ugh, It may be superior in every way (I haven't had time to read up on how or why yet) but the name? Has no one at Google ever developed in the Apple ecosystem? I know it's been 10 years but still..
It's not as bad as Microsoft though, with the word "Unity" - both a game development platform and an IOC container. Had loads of fun googling help for the IOC container when 90% of the results were about the game dev platform - also in C#.
The first half of the article started to feel like the XKCD "15th standard" meme, but at the end, the more nuanced point was presented: If you're already using Rust, stick with Rust. Carbon is positioned as successor language for those with large C++ codebases difficult to convert to Rust.
Interesting tact, and at face value that concession might undermine adoption given that Rust has a big head start and not hinged to a corp with a well-earned reputation for killing projects.
Not a C++ programmer, but I'd like to ask: Are Carbon's goals for interop here sufficient for most libraries and frameworks, or will bridge code be required in most cases?
I see this about exceptions, for instance:
"Carbon may not provide seamless interoperability support for C++ exceptions. For example, translating C++ exceptions to or from Carbon errors might require annotations or bridge code, and those translations may have some performance overhead or lose information. Furthermore, if Carbon code calls a C++ function without suitable annotations or bridging, and that function exits with an exception, the program might terminate."
That’s what I was getting at. I hope they get some real feedback from Nvidia, AMD, Intel, Qualcomm, etc before making something that is really only useful at Google.
I've been seeing a lot of references to this across youtube, reddit etc for a new experimental language. Is google putting their full weight behind this like Go or is the virality just incidental?
Lots of people are interested in replacing C++. They disagree about what the replacement should be, to some extent because what they think is wrong with C++ can be quite different.
This is a team of people with serious C++ backgrounds, who explicitly are interested in this as a successor to C++. Some of these are people who worked on P2137 which is the "Goals and priorities" paper that the committee explicitly rejected for C++ 20, so they know what they think C++ should be, and they know WG21 doesn't want that, so if they do want it they're going to need a separate vehicle to get there.
Also they're far from finished, so there's the attraction that Carbon could be whatever it is you want, while something like Rust has decided what it is.
Although it has both advantages, disadvantages and it's still being in an experiment phase, it's definitely a refreshing feeling in terms of syntax compared to C++. Tried with various different examples with different basic usage and wrote a detailed guide. If you want to get a quick feeling of how it looks like in terms of syntax, check this beginner tutorial.
Is there already a substantial amount of this in Google’s repos? It would be in character for them to reveal this after it’s already well-established internally.
There's enough gaps in the specification (move/copy situation in particular) that would make me hesitant to use this for any production code. Given that the code seems to date from WG21's rejection of the Google-led "we want to add a hard ABI break in C++23" proposal, the project is barely 2 years from literal first commit, which is likely too short to attract any substantial internal usage.
I don't think one should consider any language with a garbage collector a replacement for C++. I love Go but in my opinion it serves a different purpose than C++ or Rust.
How to make your replacement for a C language Google-able: name it after an API for a C language:
Carbon was one of two primary C-based application programming interfaces (APIs) developed by Apple for the macOS (formerly Mac OS X and OS X) operating system.
Compare also keywords or key terms:
Carbon will be built on a foundation on modern programming principles, including a generics system, that would remove the need to check and recheck the code for each instantiation. Another much needed feature lacking in C++ is memory safety. Memory access bugs are one of the largest culprits of security exploits. Carbon designers will look for ways to better track uninitialized states, design APIs and idioms that support dynamic bounds checks, and build a comprehensive default debug build mode. Over time, the designers plan to build a safe Carbon subset.
Versus...
Carbon libraries are extensively cleaned up, modernized and better "protected". While the Mac OS was filled with APIs that shared memory to pass data, under Carbon all such access was re-implemented using accessor subroutines on opaque data types. This allowed Carbon to support true multitasking and memory protection, features Mac developers had been requesting for a decade.
At first I wanted to disagree (I remember the whole "Cocoa or Carbon" dilemma for Mac developers in the early 00s), but then I just realized that I'm old.
Carbon (the Mac API) only existed to enable developers to more easily port Mac 8/9 applications to OS X, which was over 20 years ago. The Carbon API was officially discontinued in 2019 with Catalina.
The Carbon API served its purpose, it's now officially "dead", so I agree - I don't see much of an issue with giving a new technology the same name.
Are you kidding? There's tons of other words that start with C. And why would it need to anyway?
This trend of not putting any thought into what you name your language/framework/application is fairly new and shows serious laziness. Google's team should have done better. Naming things is hard but if you're going to make something worth people's time, it's worth spending a little more effort than they did.
If you cannot write a naive "carbon" compiler as a small team or even an normally skilled individual in a reasonable amount of time and effort, same abomination than c++ syntax, next.
I would say the number one weakness of C++ is its model of copy by default and often by surprise. For example: f(std::move(x)) will copy x if x is const or f takes its value by const ref - rather than a compiler error as you might reasonably expect (if you don't know the C++ reference model inside out).
In Rust, moves are destructive (which simplifies implementions - you don't need an "empty" state) and always bitwise (which is usually fine, so long as they're destructive); and copies are always explicit so you don't have the above problem. I personally think that is all more useful than the borrow checker.
If Carbon has the same bizarre move/copy rules as C++ then the effort is wasted IMO.