Carbon Language: An experimental successor to C++
github.com
github.com
1. The ability to interoperate with a wide variety of code, such as classes/structs and templates, not just free functions.
2. A willingness to expose the idioms of C++ into Carbon code, and the other way around, when necessary to maximize performance of the interoperability layer.
3. The use of wrappers and generic programming, including templates, to minimize or eliminate runtime overhead.
In otherwords, what carbon can do that Rust can't do, is take a C++ class with a `foo` method and call that method. Or create a class with a `foo` method and call that method from C++. Probably one of the biggest hurdles to get over in C++ interopt. Most don't do that, instead you'd make a C function binding and struct and move data/invoke functions through that. import stdio;
and it will compile stdio.h with the builtin C compiler, making all the declarations in it available to your D code.it's possible to do Qt without moc even in C++ with https://github.com/woboq/verdigris/, why wouldn't it be possible from D ? it should be even easier considering that D traits allow reflection of member and function names, etc.
Your perception (and mine) that rust is about to become the new default for "true native" is perfectly consistent with this, a language for the rust generation for when they have to deal with the c++ legacy. A legacy that won't be going away any time soon. I suspect that the author (authors?) wouldn't disagree at all with "use Rust when possible, Carbon when you can't", my perception (from a quick glance at the site) is that they are fully aware of the limitations of the niche they have so clearly staked out.
The evidence seems to suggest the opposite. Other than a lot of talk on programming fashion publications that are always more aspirational than representative (such as this site) Rust seems to have reached 0.3% of the market [1], up from 0.1% a couple of years ago [2], and while that is ok growth, programming languages with few exception tend to reach, approach, or at least point toward their all-time peak market penetration around age 10, and Rust is already 7. Any language could, of course, be an exception to historical trends, but there's nothing to suggest that is the case.
More anecdotal adoption stories are just as bleak. Even at this relatively advanced age, many companies dabble in Rust — as they did in, say, Haskell — but not many established companies have yet to really bet big on it.
The only positive is that among the low-level languages discussed on aspirational sites, Rust is, indeed, the most talked-about language, but history also suggests that that is a very bad predictor of long-term market success.
[1]: https://www.devjobsscanner.com/blog/top-8-most-demanded-lang...
[2]: https://www.hiringlab.org/2019/11/19/todays-top-tech-skills/
Convergent evolution. Rusty syntax is pretty close to what you get if you want to make a language look broadly similar to C/C++ while avoiding pathological and/or computationally difficult parsing.
It will take a very long time for Rust to get even close to the huge amount of C++ code out there. There are more than 5 million professional C++ developers employed around the world today. And that number is increasing. Don’t get me wrong: I like Rust and other attempts to move beyond C++. But don’t underestimate how much C++ code has been written the last 30+ years. And new C++ projects are started every single day. There are probably more C++ projects started every day than Rust projects. So anything that makes it possible to move beyond C++ while being 100% interoperable is good news.
I'm interested in seeing how things are handled with the Linux kernel's rust support, if it ever becomes more than a proof of concept. That will be a good viability test.
Lol. Gave me a good chuckle!
Also D objects have a different lifetimes & requirements, which complicates things ( see https://dlang.org/spec/cpp_interface.html#lifetime-managemen... )
Carbon appears to be auto-generating bi-directional bindings, and since it has the same memory model has no such awkward interactions between non-GC'd and GC'd worlds like D does.
Does Carbon actually solve these issues, though? It would be great if it did, but they don't list complete interop w/ C++ as an actual goal of theirs, only enough to make it practically viable for development.
Rusty syntax is objectively superior to almost everything else we've come up with, there's no reason it shouldn't be copied.
Definitly safer than C and C++ in regards to bounds checking and numeric conversions, but without any language protection against user after free, other than what you would already get with heap debuggers on C and C++.
As nice as a greenfield language with a clean ffi would be, "extremely close ties to C++" is Carbon's primary benefit.
Kotlin is another such widely liked language that was designed entirely around interop with a different language.
Typescript is a superset of javascript and intentionally short sighted to fill a current need.
One problem is that it's hard to understand the code. The whole thing is one giant proc macro, which is by itself tricky to run and debug. Also it uses techniques like implementing Deref to simulate inheritance which makes it even more confusing.
The main problem is the difficulty in extending it. Support for std::string and std::vector are "baked in" in a way that does not generalize. I tried to add support for std::wstring and it is quite non-trivial.
Because it is a proc macro it's also tricky to integrate into a build system.
To me it seems like Cxx is "purpose built" which is fine. But after working with it, I longed for a Python script that just populates a template string or something.
It actually can't ever be, because C++ has move constructors and Rust deliberately doesn't, so you can't for example return `std::string` from a Rust function by value.
I was frankly shocked by that goals and priorities document. The non-goals section reads like an open declaration of war against anyone whose use cases for C++ differ from GOOG and NVDA. My interpretation of Carbon is that since GOOG failed to take over the standard in favor of its narrow use cases, that they are building a new language optimized specifically for them.
> I have no idea ... how open to non-Google ideas it will be.
The most-generous attitude to take is that it will be managed similarly to Go. If your use cases and priorities are well-aligned with theirs, then feel free to use it. But while they may listen to third-party feedback, it will be their own use cases and opinions which dominate the language's development.
Success for the Carbon Language requires it to successfully be an independent and community driven project. We may not succeed (this really is an experiment), but we're working hard to engage broadly and early in large part because of this being such an important goal and priority for us.
Projects like this have to start somewhere, but can grow and become community endeavors. We are also already seeing strong interest from other companies and organizations in participating in this experiment.
In Rust for example, `unsafe {}` blocks are not just "local unsafety". They can freely operate on all memory, so they are infectious and are essentially a marker for "dangerous code below, be extra careful and audit lots".
But if all code can freely interoperate with C++, how do you improve upon C++, apart from relatively isolated features like a better generics system?
To what extend can a Carbon compiler that is deeply aware of C++ semantics mitigate the pitfalls?
Why use these stock index abbrevs (or whatever they are) in this context here? GEEZ!
To the topic, it sounds a bit grumpy. If we look at languages and how many evolve... many suffer the phenomenon that they almost all are Turing complete, and try to gain concise (or simple understandable) expressiveness somehow, and then they try to not break compatibility too much to varying degrees - net result: they grow and grow where at one point they feel like too big, too much legacy dragged around (C++), the "one obvious way" lost (Python) when they cater for use case after use case.
Limiting can be good in that regard. So having key goals defined and not to cater to every small new usecase by someone is a valid attempt to not let this happen, so while I dislike Googles power, I wouldn't feel to bad with attempting this by anyone on their fresh language?!
> That said, our experience, use cases, and needs are clearly not those of every user. We aren’t pushing to directly build consensus on these points. Rather, this is presented as a vehicle to advertise our needs from C++ as a high-performance systems language.
The point of the non-goals is simply stating things they don't care about, which is pretty reasonable. After all, it's easy to say what you want, but what are you willing to give up for it?
Implementing a coherent vision might lead to a better language even if most stakeholders might disagree with every single change.
Compare C++ <random> or <chrono> against, say, the equivalent functionality in Rust, Go, Java, C#, etc. C++'s APIs are a bit overcomplicated, or at least they look that way if you don't know the various reasons why the C++ standard defined them that way (reasons which are probably not relevant to your use cases).
This always felt eye-rolling false to me. We can't have a better hashmap since we all need to pay for the std::unordered_map's un-needed features like bucket access. We are certainly paying for what we don't use.
This doesn't give me much confidence if its Corporate governance rather than open governance.
It may have been started by mostly Googlers but they want other companies and individuals to participate
I think this is going to be an uphill battle for them and I hope they win it but I'll be skeptical unless if I start seeing radical (for google) transparency basically immediately.
Also worth pointing out that the language is not immediately worthless even if they fail or only partially succeed in this endeavor!!
Disclosure: Former Google engineer who worked sorta adjacent to some of those people.
- I don't use golang - As an outsider, the governance has seemed unhealthy like with how dependency management was dropped out of no where
However, it has been relatively successful. Dart's success has been more mixed. I am also looking more broadly at projects like Bazel.
> Overall, Carbon is making a compromise around safety in order to give a path for C++ to evolve. C++ developers must be comfortable migrating their codebases, and able to do so in a largely automated manner. In order to achieve automated migration, Carbon cannot require fundamental redesigns of migrated C++ code. While a migration tool could in theory mark all migrated code as unsafe, Carbon should use a safety strategy that degrades gracefully and offers improvements for C++ code, whether migrated or not.
> That does not mean Carbon will never adopt guaranteed safety by default, only that performance and migration of C++ code takes priority, and any design will need to be considered in the context of other goals. It should still be possible to adopt guaranteed safety later, although it will require identifying a migration path.
That's very interesting and pragmatic. It would be interesting if they can eventually come up with the same level of safety guarantees via a different path than Rust's borrow checker.
-------------
Since one of their goals is to automatically translate modern C++ to Carbon, I do wonder how well that is going to work in general.
I definitely welcome an alternative to C++ that would be easier to read and understand. That would be a benefit to the world.
It's not like PHP is unsafe to begin with like C++, but the language does have a ton of problems, and Meta's massive codebase could only be migrated to another language gradually. Hence, Hack. Better language, better tooling, more productive programmers.
Note that unlike Carbon/C++, Hack is backwards-compatible with PHP. So the migration is somewhat more gradual.
For instance, just like the -O1 or -O3 flags work for optimization, something like a -S1 or -S3 would be really useful.
To me, there are lots of times when I just need to get an idea into code. Then there are times when I need to make sure that code just works™.
Having different compiler flags would really make that nice, and for devops, allow anything pushed to production have to complete a -S3 successfully first.
This seems like Google’s response to
1. Rust not being sufficiently “Go-like” (in the sense of the “The key point here is our programmers are Googlers, they're not researchers” quote) where C++ lets a bunch of people who are not really experts in the language write footguns that Google has to deal with when they cause problems at scale. They want a dumbed-down language (some would use words like approachable/safer/whatever here) for them so nobody will send in CLs with ”clever” code that causes headaches later. I guess they’ll need to have generics but I’m guessing that choices will be made to avoid introducing advanced type theory, functional programming, etc into the language.
2. Google uses C++ differently than everyone else who uses C++. In particular, they have a lot of statically linked code from a monorepo that gets recompiled all the time. This has caused them to put up proposals to “fix” the language that nobody else will support and don’t get adopted, because they break the ABI or backwards compatibility in ways that are unacceptable to the others who participate. It seems like this language is the result of that frustration and subsequent soft-withdrawal from the C++ WG.
I haven’t looked at the design much yet beyond just the simple examples and I think it mostly looks reasonable, but I feel like Google designed this to solve their problems with C++ and is just throwing it out there if people are willing to adopt it because it’s there and Google says it’s good, just like how Go gained traction. Sometimes Google does make good things :) Some Go developers would say that about Go, I’m sure. But if you’re using this, it seems pretty clear that the needs of this will be driven by Google, and the above two points are probably things you should keep in mind as you watch it evolve.
> Seamless interop where safe Rust APIs are made callable from C++ requires C++ users to follow Rust borrow checking rules.
Their complaints about borrow checking rules at the interop layer ring hollow to me. Whether the new code is being written in Rust, Carbon, or C++... the lifetime of shared memory must be well-understood by the developer writing the code. Rust just makes this problem explicit and enforceable. Sweeping the problem under the rug isn't a better option.
> However Rust imposes stricter rules than C++, disallowing some design choices that were valid in C++.
The word "valid" is doing a lot of heavy lifting here, and I'm generally skeptical of these "valid" architectures. If it is so easy to know that these architectures are valid, why do we still see so many memory safety issues in Google's C++ code? Incrementally restructuring C++ code to be more provably correct doesn't sound like a terrible thing... in fact, it sounds like exactly what they should be doing.
> However, we are not certain that [C++ can be migrated to Rust incrementally]
Firefox is a large, historically C++ codebase that has undergone incremental rewrite into Rust for years now. It seems quite certain that this is both possible and practical! Where is the uncertainty? Of course, Mozilla's budget pales in comparison to Google's.
Rust is an extremely extensible language, and it is absolutely possible for Google to build their own version of `rust-bindgen` that suits their particular C++ codebase's idioms. That would be a much simpler undertaking that achieves their goal of incrementally adopting memory safety.
I hate to disparage new languages, but this feels like Swift all over again... it's just NIH. At this point, the die has been cast, and I'm sure it would be career suicide in Google for anyone behind the Carbon project to admit at this stage that "actually, the project turned out to be unnecessary after a discussion on HN!", so I don't expect to change anyone's mind. I'm just wasting my breath making obvious counterarguments that I'm sure have already been considered and ignored.
To be extra clear, I would love to see a company like Google take on the challenge of building an ergonomic language that exceeds Rust in terms of safety, but Carbon is a half-measure that doesn't pretend otherwise. If all of Google's C++ code is magically rewritten in Carbon, they will still apparently have memory safety problems based on what Carbon's README says... and then it'll be time once again to consider "maybe we should have ported to Rust after all". It just feels like such a waste.
It's actually a big problem. There's a whole lot of Rust library API's that are only provided with an idiomatic "safe" interface, but this actually imposes stronger, more demanding preconditions on those API calls than are warranted by the actual code, which could easily work with e.g. raw (possibly aliased) pointers, or owned-but-pinned (non-movable) data. This creates unneeded pitfalls in Rust-C/C++ interop. The counterargument is that future versions of that library code might benefit from those stronger preconditions, but that's more of a theoretical point, it just doesn't apply in most cases.
If they needed to fork the Rust compiler to pessimize a few optimizations that the Rust compiler would normally do (that would invalidate such unsafe C++ code with additional UB), even that would be far less effort than inventing their own entire new language and ecosystem from scratch. That is without considering how Google could work with the Rust Core Team to contribute solutions for ergonomic issues they're encountering in the interop process.
When the alternative is "building an entire, general purpose programming language", there are a lot of other things you can do that would be much easier.
And, as previously mentioned, Carbon is only addressing the low hanging fruit... it isn't stated anywhere I've seen that they even intend to achieve parity with Rust. All of this effort, just for a lesser outcome.
I'm sorry that I'm frustrated at big companies choosing to take half measures that seem even more expensive than the full measure. I have used Rust professionally for years; I'm clearly biased, but it's not that hard. The level of safety that Rust provides should be table stakes in discussions of unmanaged languages... not the ceiling for what we can possibly imagine, but Carbon is a statement that Rust's bar is too high for Google to reach, and that's pretty depressing.
I doubt that Chandler would lose his job if this project is abandoned. In fact, I'd say chances it is abandoned (at least, mothballed, never to be revived) are significant so if Chandler's job does hang on this work that was a bad idea. It's an experiment, I personally think it's looking in the wrong place, but of course the point of experiments is that you don't know what the results will be. I doubt that Chandler has labelled this an experiment without knowing that.
So, my expectation is that probably Carbon won't even complete design, but if Chandler leaves Google that won't be why.
That's really not true and we can look at other languages to see the various amounts of un-true it is.
If ABI constantly changes then what you said is possibly true, but nobody is actually proposing that. The idea instead would be breakage along a std version. Like C++23 would be an ABI break. In the same way Java has had various ABI breaks over the years. You'd be blocked on taking the new ABI until all your dependencies have released updates, sure, but this isn't unheard of or unsolvable.
It's also pretty much what you expect from any semvar library, too. API/ABI breaks are quite common outside of monorepos, after all. As long as it's appropriately documented (such as with a major version bump) and there's appropriate dependency tracking, the world can handle it fine.
The C++ committee seems to be extremely shy from going this route, though. Even though C++11 triggered some ABI breaks ( https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_a... ) and everyone seems to have gotten along with that just fine.
You just ship 2 version compiled targets of std libs
- I wonder how much baggage had to be maintained for interop. If some of it could be isolated, how did they do it?
- Does this fall into any of the traps that D initially did where it allowed C interop but was, by default, more limited in what C environments it could run in or is this as flexible as C++ for environments?
As for the language itself, I've not had a chance to dig into it too much but I am sad to see that it uses explicit local inference by replacing the type name with `auto` rather than eliding the type completely [0]. While it has its pains at times, this is something I've come to enjoy in Rust.
I also didn't see mention of tooling. Having out-of-the-box build, test, and code formatting would be a big help for establishing community standards / practices, even if the build/test tool might get limited when having to do C++ interop. At least for pure-Carbon libraries it would be a big help!
> Once we can migrate code into Carbon, we will have a simplified language with room in the design space to add any necessary annotations or features, and infrastructure like generics to support safer design patterns. Longer term, we will build on this to introduce a safe Carbon subset. This will be a large and complex undertaking, and won't be in the 0.1 design. Meanwhile, we are closely watching and learning from efforts to add memory safe semantics onto C++ such as Rust-inspired lifetime annotations.
I'm a bit skeptical if they push off lifetime annotations too far.
[0] https://github.com/carbon-language/carbon-lang/blob/trunk/do...
// A dynamically sized array, like `std::vector`.
var circles: Array(Circle) = ({.r = 1.0}, {.r = 2.0});
Yegads, they've put effort into ensuring API and ABI compatibility with C++, but they've gone and decided to change the meaning of nouns for basic types?!Why, just why would introducing that obvious footgun be appealing? It raises the concern that the language is full of other arbitrary choices hiding dangerous footguns.
Edit:
Strangely, their test suite makes it look like Array is bounds checked and fixed size; there is no test for resizing:
https://github.com/carbon-language/carbon-lang/tree/trunk/ex...
Other languages don't need to replicate this mistake.
var kek: array of int;
setlength(kek, 666); // kek is now int[666]
setlength(kek, 1337); // kek is now int[1337]
Zig: ArrayList
GLib: GArray
Objective-C: NSMutableArray
So List would have been the more Java/Zig way to name it (also Python, etc.)
1. std::vector doesn't have a fixed dimensionality, as would a mathematical vector. A fixed-length array actually makes more sense as a vector.
2. It doesn't provide the operations of addition and multiplication by scalars out-of-the-box (though you can whip up your own). Moreover, in general those operations wouldn't make sense for the elements which can be stored in a std::vector. E.g. neither multiplying bank account numbers by scalars, nor adding two bank account numbers make any sense. It would be good if you modelled them with types which don't allow those operations. Yet storing them in a std::vector makes perfect sense. But std::vector (or tuple) of bank account numbers is not a vector.
2. Operations are not intrinsic to a set, but to an algebra. Why would there need to be any correspondence between the operations of linear algebra and those of banking algebra in order to call an std::vector a vector?
Link to lecture by Stepanov: https://www.youtube.com/watch?v=etZgaSjzqlU
Furthermore in his book "From Mathematics to Generic Programming", Stepanov says that if he could change its name, he'd have named it "array".
No, because you can't prove that std::vector<T> obeys all vector space axioms[1] for all T, which is good because it's impossible, I can trivially define a T that will break any number of axioms and the cpp compiler will happily let me instantiate std::vector on it.
[1] https://www.math.ucla.edu/~tao/resource/general/121.1.00s/ve...
The Java Vector features will be out of incubator in the next year or so and unlike the existing Vector, it's actually useful. For context the new vector features are for SIMD support on the JVM.
I only know about it from dealing with J2ME crap where ArrayList wasn't available.
Mathematicians are probably better suited to using R, Julia, Octave, or Wolfram.
This now looks to me like a Rust-- instead of a C++++, which is a picture they might not want to give rise to. Because then I'd rather use Rust instead, which then feels like the real thing(tm).
[EDIT: If you think about downvoting, maybe answer instead as I am genuinely interested in this syntax question. I am not trying to be negative, it was just an observation and a question.]
As for what's wrong with `Type name(constructor, args)`? A lot of tooling wants to be able to parse "mostly-valid C++", like IDEs and compiler diagnostics. Sure, once clang's type inference is finished, the lexer hack and most vexing parse aren't problems, but when the program isn't complete, parsing isolated fragments is impossible, and that limits the amount of useful tooling the language can have.
Even better, when you start having more complex patterns on the left-hand side of `=`, you can type annotate them as you want. Hypothetical syntax would be:
var (x: f32, y, [z1,z2,z3]) = SomeExpression();
That's harder to do when you have a type declaration on the left imho. five: integer = 5
or integer five = 5`fn`, `name: Type`, `i32`, `->` for return type. `impl` as a keyword. `Self` as a keyword.
Nothing unique to Rust, but it's interesting to see.
You can parse Go without a symbol table, but not C, because stuff like
item *a;
changes completely in meaning depending on the existence of a previous typedef for `item`.C++ in order to not break compatibility with C has elevated this to insane extremes - there's so much ambiguous syntax in the language.
x = b.get<item>(r);
This expression can either be a function invocation, if `item` is a type and a template method named `get` exists, or else it's a series of comparisons. item f(r, f);
is also ambiguous: if r and f are types, that's a function, otherwise that's a variable declaration. There's no way to know that unless you have a symbol table, which makes separating syntactical and semantic analysis impossibile at best.The whole C++ language is full of similar ambiguities, and attempts to fix warts that backfired spectacularly. That's also the reason why writing a C++ frontend is a decade long endeavor that takes lots of people and resources. A full time team of 3 people can probably write a C parser in a few weeks in comparison, and C is big mess too, albeit a smaller mess though.
[1] https://elizarov.medium.com/types-are-moving-to-the-right-22...
x:Type has been used in MLs (SML, Ocaml) and recently TS. Haskells uses x::Type. This usage dates back to at least the simply typed lambda calculus in the 1930s.
fn and fun are used in SML and probably elsewhere. fun is used in OCaml, as well.
> 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 a modern generics system, modular code organization, and consistent, simple syntax.
That last part seems to imply that the authors don't consider C++ syntax to be a good foundation for a modern successor language, so they chose to change it. As to why change it in a Rust-like direction I'd imagine that it's both because it's what fashionable at the time and possibly to attract people who are already familiar with that style.
C#++ would be the next one, but I'd pull what Microsoft did to Windows 9 and skip right to C##.
The rest I can excuse but [], I cannot. Same reason I won't touch Nim.
The real solution is [] for generics and something else for indexing.
> The Chrome security team is working to make a cross-platform memory safe language available to Chromium developers. This document describes how to use that language in Chromium. The language, at least for now, is Rust.
Could this mean that the "at least for now" part might hint to the language discussed in this thread? Memory safety seems to be a core goal of Carbon [1]:
> Safer fundamentals, and an incremental path towards a memory-safe subset
This approach could make sense, looking at their large C++ code base in Chrome.
[0]: https://news.ycombinator.com/item?id=31830020 [1]: https://github.com/carbon-language/carbon-lang
But, right now Carbon doesn't have a better solution, it only has an ambition to build an incremental path toward being able to be a solution.
Importantly it has an ambition but it has no proposal for how to get there. There are other safe languages, but AFAIK none of them launched with "Eh, we'll do safety later, I'm sure we don't need to start with it". The ones I'm thinking of all began with their safety principles and then they added cool features which were inspired by those principles.
I reckon that even if that's not directly causal, it means the culture associated with these "We'll do safety later" languages doesn't prioritise safety highly enough. So ambition or not, they aren't going to put the hard work in to make it actually happen.
Rust provides many of these, but not much of an incremental path there. Carbon aims to provide many of these, but not as much safety as Rust (likely, even in the future). The upshot: there are tradeoffs, and we'll need to watch our options and make continual decisions as to the best courses of action. Such courses may differ by area of the project; it's possible we might choose to write some hardened services in Rust communicating via Mojo with mixed C++/Carbon code.
> Rust provides many of these, but not much of an incremental path there
The incremental path is provided since you can refactor stuff into Rust at a scale as tiny as individual functions. Even an "unidiomatic", C/C++-like interface to "unidiomatic" unsafe Rust code is better than the status quo where no safe subset of the language can possibly exist.
The Rust borrow checking approach does a very good job of establishing memory safety in a way that respects compositionality and module boundaries; most proposed alternatives do not engage with this obvious concern at all. Pre-"Modern" C/C++ idioms are inherently unviable because proving them safe is a global, program-wide concern. The Core C++ Guidelines developers are quite aware of this, which is why Guidelines-compliant code is quite rusty already.
And as to your initial comment, of course safety is important, but if you don't understand why things like maintainability and performance are _also_ critically important, then your opinion is not sufficiently well-informed.
> Interoperate with your existing C++ code, from inheritance to templates
Somewhere in the docs (can't remember where) is a link to a Rust/C++ interop project sponsored by Google, Crubit:
https://github.com/google/crubit/blob/main/docs/design.md
In case it's not clear, Carbon is also at the moment a Google project.
There's not much in the Crubit README (although there is a warning not to use it), but the docs directory has some interesting stuff:
> The primary goal of C++/Rust interop tooling is to enable Rust to be used side-by-side with C++ in large existing codebases.
https://github.com/google/crubit/blob/main/docs/design.md
It's not entirely clear whether this interop is to work as envisioned for Carbon (source level?) or some other approach.
Developers need better and unique names for their products. I realize no one will care because no one is using it anymore, but Carbon was already taken by Apple for their Objective C API.[1] That both are pretty much in the same space with the same name is sure not to cause any confusion.
Google did clobber another programming language with Go.[1] It was a truly a-hole move.
[1] https://en.wikipedia.org/wiki/Go_(programming_language)#Nami...
Not even a tiny little bit? Really?
First of all, apologies for my boneheaded mistake, but let me try to see if I can show you the problem. If everything, everything there is, was named "Tom," you can see how it might get confusing determining just what is being talked about. That is hyperbole, but it should illuminate why it is ambiguous to call two things by the same name, but it is even more so when these two things with the same name operate in the same space.
But wait, you say, they are entirely different and unrelated! You think no one will be confused, because one Carbon is a programming language possibly based on C++ and the other is a C programming language API. Totally different, huh?
In fact, they're in the same space, programming. One Carbon is a language, the other a application programming interface for another programming language. They're also more or less dealing with the same programming language. I realize C is not C++, but without C there would be no C++, so they are very strongly related, along with ObjC. Fundamentally, these languages are all C, the newer ones using the same syntax but with advanced features not found in C. Still C, if we're being handwavy, and we definitely are.
So now, whenever someone mentions Carbon somewhere, like, "use Carbon!" That will be ambiguous due to this developer's unfortunate lack of nomenclature creativity.
Does that help at all to reveal why a new programming language based on C++ should probably chose a unique name rather than recycle a name that is still in use to refer to a C API? Since Apple already chose Carbon for their C API, and since it is so well established, even if it is no longer used, and since it is just not that old, and it when it was current, it was everywhere Apple, then it takes priority. So the arbitrary name this developer chose will inherently cause confusion, inevitably, because another Carbon already exists in the programming space.
Why not call it "Centigrade?" Or "lightspeed?" Because calling a C++-based language "Carbon" because it is based on C++ is not remotely as clever as Apple calling their C API Carbon because C is the symbol for Carbon, and not C++, which itself is a great name for a programminglanguage because it will never be confused with anything else, because afaik nothing other than C++ is called C++.
Let me know if you need more explanation why Carbon is an unfortunate name for anything new in the programming world. If it was, idk, the name of a publishing company or something, it wouldn't matter. It only matters because these things are in the same space.
As a practical illustration, it'll cause confusion when searching for 'carbon programming' or 'carbon apis' on $SEARCH_ENGINE. It isn't current but I would wager that there is still a lot of legacy Carbon code in the Macspace. This won't help the poor devs tasked with maintaining it. Unless they rewrite it in Carbon. See?
We in the trade also know how important it is to avoid giving things confusing names, and how frustrating it is when you find some garbled or ambiguous variable name while debugging or enhancing code. The same principle applies to naming your language too.
Only mention of those terms seems to be https://github.com/carbon-language/carbon-lang/issues/505 which seems like weak evidence against naming conjecture.
I'll now go away for a few years until the dust settles.
- function and variable types are harder to visually parse for me. The keyword to declare a variable and the type put the varible name in the middle for instance.
- the "fn" keyword is terrible, just to save on characters. Honestly, any keyword should have vowels and is pronounceable. Python has "def", I would have been fine with "func" as well
- type annotation for templatization make is hard to read where the real arguments begin (for me). I puts info on the type in another place than the variable itself.
- "Mutable" feels like it should be all lowercase, to stand out.
In general, I know there are areas to improve on C++ syntax, especially on modules, but some choices seem different just for the sake of difference.
Translating C++ to Rust is too hard - the underlying data models are too different. What would be really useful would be something that intelligently translates pointer-based C++ code into a slice-based language. Every place there's an unsized array, something has to figure out how big it is and pass that info around. In the original program, that information had to be present in some form. The trick is finding it. That's probably not out of reach for a static analyzer today. Especially if machine learning is used to help find the usual idioms of C/C++. First find, then check.
Very important. A C++ alternative and successor needs to be compatible with C++.
The rest of these so called C++ alternatives are either rewriting everything in their own language and causing chaos with their own incompatibilities with their language features and realising that it wasn't a good idea after all to do such rewrites after being sold vacuous promises and language feature snake oil, but only to show pretty syntax sugar.
Unfortunately, the hype squads will just attempt to drown out other alternatives like this one; even if it works with the existing C++ ecosystem.
This paper goes into the details https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p18...
> Broader field experience required
> Sustained interest to use Carbon from multiple organizations and individuals
> Prototype implementation
> Demonstration of potential
> Learning material
> Prepare for new contributions and feedback
> Launch event
> Relationship to C++
> Perception of ownership by a single organization
Is this post considered as a step towards going public?
Also thanks for adding sum types, and pattern matching, is there anyway you could get the dart team on board? They seem to be averse to them and it's a big reason why I don't use the Dart/Flutter ecosystem.
I'm driving the design of pattern matching for Dart. The entire language team is on board with them and we have a design that's pretty far along. It's really hard to integrate pattern matching into a language that wasn't originally designed for it, so it's taken a while to settle on a syntax that makes sense, but I think we're getting close.
If you'd like to be involved, there is a category on the issue tracker for design discussions related to patterns and records:
https://github.com/dart-lang/language/issues?q=is%3Aissue+is...
Just like Kotlin did to Java
The only viable alternative to C++ imo
I like the verbosity of a language like pascal, but I just find it jarring in a C replacement these days. (and rust's structure definitions/etc I just find needlessly verbose for the way I use C structures).
C is nice because its fairly easy to mentally parse (C++ less so) vs some of the alternatives, while still being extremely concise.
std::vector<std::unordered_map<std::string, std::pair<std::string, std::string>>> foo(std::vector<std::vector<int>> x, std::unordered_map<std::string, std::string> y); using namespace std;
typedef vector<unordered_map<string, pair<string, string>> foo_bar_xref;
foo_bar_xref foo( vector<vector<int>> x, unordered_map<string, string> y);
not sprinkling std:: everywhere helps with readability, but so does defining a couple types used frequently, especially if they are particularly verbose. And of course the parser doesn't really have a problem with this, so your editor should be able to find it with its 'goto declaration' function. I don't feel pity for people who chose to use editors/IDEs that make this difficult.I agree, but most C++ programmers don't :/
> And of course the parser doesn't really have a problem with this, so your editor should be able to find it with its 'goto declaration' function.
C++ syntax is Turing-complete, so due to the halting problem, finding the declaration can take a long time, potentially unlimited in pathological cases.
Absolutely not unlimited time. Once it's parsed and semantically analyzed you can find the declaration in no time. Exactly like the compiler does.
edit: to clarify, I was not taking into account unbounded recursion on template instantiation, which should be limited in any case by the compiler.
using namespace std;
using foo_bar_xref = vector<unordered_map<string, pair<string, string>>;
foo_bar_xref foo( vector<vector<int>> x, unordered_map<string, string> y);Do you have an example? What's verbose about Rust struct syntax?
. Performance matching C++, an essential property for our developers.
. Seamless, bidirectional interoperability with C++, such that a library anywhere in an existing C++ stack can adopt Carbon without porting the rest.
. A gentle learning curve with reasonable familiarity for C++ developers.
. Comparable expressivity and support for existing software's design and architecture.
. Scalable migration, with some level of source-to-source translation for idiomatic C++ code.
* Source file encoding is required to be UTF-8. Strings are UTF-8. No apparent provision for binary strings, but I haven't delved into the string API.
* Retains the C/C++ definition of overflow of signed integers cannot overflow, unsigned can. That's o_O-worthy; the two should be aligned, and if they can't overflow, provide some form of wrapping integers as well.
* Yay, tuples.
* Struct type syntax is ... weird? {.name: String, .count: i32}
* Expressions. Partial order for precedence (i.e., a | b << c is ill-formed instead of being parsed as (a | b) << c or a | (b << c). The Rust-style cast syntax I think I prefer, but ^x for bitwise not is o_O, and if a then b else c feels odd for a generally C-syntax language to use. Similarly using 'and' for logical and instead of &&.
* var and let for declaring variables; one is constant, the other not--that's somewhat jarring. It seems that the : <type> is mandatory, and inferred type is : auto instead of letting it be omitted? Feels unnecessarily verbose to me.
* No goto, nor labeled break and continue. Huh. Also, 'for (var name: String in strings)' is again feeling unnecessarily verbose... (Can break break out of an if statement, or does it have to be a loop?)
* You declare "returned var c: Circle" instead of relying on named return value optimization. Again with the verbosity, although I haven't yet reached copy/move constructor stuff to understand how much automagic happens.
* The [me: Self] syntax is weird. I'd like something closer to the C++ deducing this syntax or Rust's &self/&mut self, where the type of the this parameter is specified via the first argument rather than what feels like a somewhat-out-of-bounds information.
* Mixin (aka multiple inheritance) is unspecified at this point.
* The keyword for enums is "choice"? Really?
* Name lookup retains the C/C++ rules of need-to-declare-before-use. Again, is this really necessary? It's fiddly...
* The [me: Self] syntax appears to be a specific instance of the generalized syntax for generics, but only for method parameters, because generic types use () instead. Again, why differentiate from the C-family standard practice of <> for generics? Also, the : versus :! in generics strikes me as overdrawing the weirdness budget one too many times. Props for using something closer to a constexpr if than C++ SFINAE; SFINAE is not a design model I would carry forward in any future languages.
* Stable ABI appears to purely be defined in C ABI terms. Sigh, can we get people on these language committees together to start thinking about post-C standardized ABIs?
* Async, coroutine, lambda stories are unclear.
* Error handling also unclear. (That's kinda important!)
* 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.
Agreed, they should provide three kinds of integers: signed as usual, unsigned like in C++ but for compatibility only, usage discouraged (unless your programming a clock) and "natural integers" which traps on over/under-flow in debug builds. And going from one kind to another kind should always be done with explicit cast (there is a proposal to allow some implicit conversions and it allows implicit conversion from unsigned to bigger signed :-( :-( )
Pro tip: Don't try to migrate an entire catalog of functions all at once to Rust (or pick your favorite C++ alternative). Pluck off individual pieces and use FFI to bridge the gap. Remember, work incrementally.
However Carbon seems to do a whole lot more than DevEx. It’s practically a whole new language that can interop with C++. I don’t see the point in that. Would be great if someone pointed out why I should change my mind.
Here is my attempt, since 2011:
Works nicely, unlike the Java Behemoth.
Dart does the same, but its justification is the (excessive) amount of indenting going on. It's often a struggle to match indents visually.
(I initially assumed they had some syntactic sugar for smart pointers.)
Enough said! I agree.
Clang and llvm understand them, and you can require them from the front end, but the cost is some backends will hard error on them as unimplemented.
Tail calls mean reusing memory (notably the stack) and arranging for there to be no work to do between the call and the return. E.g. if arguments are passed by allocating on the stack, you can't deallocate after the call, so you have to make the stack look just right before jumping.
If you've got multiple calling conventions on your architecture, they each need their own magic to make tail calls work, so you might have 'fastcall' work and 'stdcall' error. Iirc I implemented it for a normal calling convention on one arch and didn't bother for variadic calls.
I suppose one could have a dedicated convention for tail calls as well, I just haven't seen it done that way. Usually the callee doesn't know and can't tell whether it was called or tail-called.
Obviously not…
Which is to say, "Not at all".
one reason I use golang over c++ is the network, for c++ network socket Unix and Windows are totally different(winsock vs bsd socket), while golang works well at both OSes.
I guess now it is clear where Google's clang contributions end up going instead.
> Disadvantages:
> - The syntax space of the return type is very crowded already, and this would add more complexity there rather than fitting in cleanly with existing declaration spaces within the body of the function.
> - Likely to be an implementation detail and valid to use on a function with a normal return type in its forward declaration. This isn't obvious when placed in the declaration position, and it might well be unnecessarily added to forward declarations just because of its position.
> - Removes the ability to both specify a specific return type and a pattern for binding parts of that object to names. Instead, the type must be inferred from the pattern. This ended up feeling like a deep and fundamental problem where we would lose important expressivity to disambiguate the return type from patterns. For example, when the return type is some form of sum type or variant, the pattern space is both especially attractive to use and fundamentally fails to express enough information to capture the type.
But I don't think a re-sugaring of syntax is enough to make people switch.
Overall I don't see myself using this. 0/3 google
The short version is that for their particular usecase they need really close ties to C++.
"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. Unfortunately, the designs of these languages present significant barriers to adoption and migration from C++. These barriers range from changes in the idiomatic design of software to performance overhead."
I don't know why google created this language. It offers nothing new and I can't see why they'd use this over rust when rust can be used. I don't see why they use this over zig since zig can certainly be used where this language is meant to be used. Zig actually brings something new
Overall google is 0/3 on creating languages that people want to use. Maybe go is useful but I haven't seen enough proof
JavaScript → TypeScript
Java → Kotlin
C++ → Carbon"
I seem to be the only one on the planet that doesn't think the language needs to be replaced.
All the time, it is C++ these companies use for these apps, especially having millions of users and generating multi-millions or hundreds of millions of dollars.
In which world has Rust replaced C++?
Although I still think it should be possible to make some things obsolete in C++. The technical debt is real, and the language can hardly improve if old codebases are slowing down the evolution of the language.
I already wrote several times that I would like a new C++-like language, but without the complexity of C++. D, zig and rust are fine but they're not simple languages to use. I want the nice things of C++ (string, a few containers, a bit of syntax sugar, the most useful std stuff), with enough simplicity from python or C.
I just use the simple parts of C++, and I only want those parts. I just want the KISS simplicity. Carbon is not that, neither is rust zig or D.
CamelCaseForEverything is such a waste, maybe they use it for implicit public/private as in Go? And maybe to please existing Go or Java users?
No thanks
Also, under "Why not Rust?"
If you want to use Rust, and it is technically and economically
viable for your project, you should use Rust. In fact, if you can
use Rust or any other established programming language, you should.
Carbon is for organizations and projects that heavily depend on C++;
for example, projects that have a lot of C++ code or use many
third-party C++ libraries.https://github.com/carbon-language/carbon-lang/blob/trunk/do...
They'll need to get it into Compiler Explorer so people can really look at codegen rather than porting small programs.
That's pretty extensively covered in the link, but here's a relevant snippet:
"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. Unfortunately, the designs of these languages present significant barriers to adoption and migration from C++. These barriers range from changes in the idiomatic design of software to performance overhead."
Interestingly, when looking at their code samples, the vibe I get is more "Go++". Using `var` for variable declarations, letter casing for visibility, explicit returns even at the end of functions, using the "package" keyword for namespacing, etc. I do see some superficial syntactic similarity to Rust, like using `fn` for functions and `->` to annotate return types, using `:` for type annotations for variables, and semicolons seeming to be required at the end of lines, but overall it doesn't really _feel_ that much like Rust to me, I think due to how imperative it seems. Given the use of `class` and `let/var` seeming to be const versus mutable bindings, I'm wondering if the Rust resemblance is actually just transitive through more of a resemblance to Swift, although I don't know Swift well enough to know if this is an accurate explanation.
`->` syntax is included in C++11 standard, named "trailing return type", but its adoption seems to be very slow.
`auto f() -> int { return 42; }`
This reminds me of Dart - another big company thinking they can invent a new language to tackle old language problems.
This is not the way to improve C++ - because this path already exists, either as D or if compatibility or OO model isn't an issue, Rust.
C++ has been improving slowly but surely - just remember that 90% (heck even more) of C++ issues stem from the hell that's compatibility with C and that's both a blessing and a curse.
If you've seen their cppcon talks, you'll see that the changes they want are not what the committee (or even the general c++ community) focuses on (for example, I couldn't care less about ranges). For example, they want to make changes to unique_ptr because the inefficiencies in the ABI cause performance issues and probably can be tracked to additional cost per month. They couldn't make these changes without changing ABI. At google scale, small inefficiencies add up so fast.
I have no doubt they looked at D and saw that it wasn't feasible (for whatever reason) and they already stated why Rust is not sufficient. They wouldn't make this decision arbitrarily and we are not privy to all the meetings that went into the decision making process.