Skip to content

Latest commit

 

History

History
659 lines (501 loc) · 31 KB

faq.md

File metadata and controls

659 lines (501 loc) · 31 KB

Project FAQ

Table of contents

What is Carbon?

The Carbon Language is an experimental successor to C++. It is an effort to explore a possible future direction for the C++ language given the difficulties improving C++.

What is Carbon's status?

Carbon is still an experiment. There remain significant open questions that we need to answer before the project can consider becoming a production effort. For now, we're focused on exploring this direction and gaining information to begin answering these questions.

How soon can we use Carbon?

Carbon is still years away — even if the experiment succeeds, it's unlikely that it will be ready for serious or production use in the next few years. Everything here is part of a long-term investigation.

Why make Carbon public while it's still an experiment?

One of the critical questions we need to answer as part of this experiment is whether the direction we're exploring with Carbon has both broad and significant interest for the industry at large. We feel like this is best answered by developing the language openly, publicly, and with broad participation.

How complete is Carbon's design?

We've resolved several of the most challenging language design technical decisions we anticipated based on experience with C++ and its constraints, particularly around generics and inheritance. Beyond those two areas, we have initial designs for class types, inheritance, operator overloading, syntactic and lexical structure, and modular code organization. We are aiming to complete the initial 0.1 language design around the end of 2022 although there are a large number of variables in that timeline. See our roadmap for details.

References:

How many people are involved in Carbon?

Prior to going public, Carbon has had a couple dozen people involved. GitHub Insights provides activity metrics.

Is there a demo?

Yes! A prototype interpreter demo explorer can be used to execute simple examples. For example:

$ bazel run //explorer -- ./explorer/testdata/print/format_only.carbon

Example source files can be found under /explorer/testdata.

Carbon can also be explored interactively on https://carbon.compiler-explorer.com.

Where should I ask questions about Carbon Language?

Please ask questions and hold discussions either by using GitHub Discussions or #language-questions on Discord.

GitHub Issues should be reserved for missing features, bugs, and anything else that is fixable by way of a Pull Request.

Why isn't there a Carbon Language logo?

Establishing a Carbon Language logo isn't a priority right now. Remember that this project is an experiment, and so we think it's best to concentrate efforts on ensuring that the language succeeds at its goals instead.

We have a few drafts in the works, but it requires a fair amount of work to get right, and getting it wrong is costly, so we won't be adding one in the near future. Don't suggest logos, because we need to be careful about how we create one.

Why build Carbon?

See the project README for an overview of the motivation for Carbon. This section dives into specific questions in that space.

Why is performance critical?

Performance is critical for many users today. A few reasons are:

  • Cost savings: Organizations with large-scale compute needs care about software performance because it reduces hardware needs.
  • Reliable latency: Environments with specific latency needs or concerns with bounding tail latency need to be able to control and improve their latency.
  • Resource constraints: Many systems have constrained CPU or memory resources that require precise control over resource usage and performance.

What level of C++ interoperability is expected?

Carbon code will be able to call C++, and the other way around, without overhead. You will be able to migrate a single library to Carbon within a C++ application, or write new Carbon on top of your existing C++ investment.

While Carbon's interoperability may not cover every last case, most C++ style guides (such as the C++ Core Guidelines or Google C++ Style Guide) steer developers away from complex C++ code that's more likely to cause issues, and we expect the vast majority of code to interoperate well.

For example, considering a pure C++ application:

A snippet of C++ code. Follow the link to read it.

It's possible to migrate a single function to Carbon:

A snippet of mixed Carbon and C++ code. Follow the link to read it.

References:

What would migrating C++ code to Carbon look like?

Migration support is a key long-term goal for Carbon.

If a migration occurs, we anticipate:

  • Migration tools that automatically translate C++ libraries to Carbon at the file or library level with minimal human assistance.
  • Bidirectional C++ interoperability that allows teams to migrate libraries in any order they choose without performance concerns or maintaining interoperability wrappers.
  • Test-driven verification that migrations are correct.

What alternatives did you consider? Why did they not work?

Why not improve C++?

A lot of effort has been invested into improving C++, but C++ is difficult to improve.

For example, although P2137 was not accepted, it formed the basis for Carbon's goals.

Why not fork C++?

While we would like to see C++ improve, we don't think that forking C++ is the right path to achieving that goal. A fork could create confusion about what code works with standard C++. We believe a successor programming language is a better approach because it gives more freedom for Carbon's design while retaining the existing C++ ecosystem investments.

Why not Rust?

If you can use Rust, ignore Carbon

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.

We believe that Rust is an excellent choice for writing software within the pure Rust ecosystem. Software written in Rust has properties that neither C++ nor Carbon have. When you need to call other languages from Rust, RPCs are a good option. Rust is also good for using APIs implemented in a different language in-process, when the cost of maintaining the FFI boundary is reasonable.

When the foreign language API is large, constantly changes, uses advanced C++ features, or makes architectural choices that are incompatible with safe Rust, maintaining a C++/Rust FFI may not be economically viable today (but it is an area of active research: cxx, autocxx, Crubit).

The Carbon community is looking for a language that existing, large, monolithic C++ codebases can incrementally adopt and have a prospect of migrating away from C++ completely. We would be very happy if Rust could be this language. However, we are not certain that:

  • Idiomatic, safe Rust can seamlessly integrate into an existing C++ codebase, similarly to how TypeScript code can be added to a large existing JavaScript codebase.
  • Developers can incrementally migrate existing C++ code to Rust, just like they can migrate JavaScript to TypeScript one file at a time, while keeping the project working.

See Carbon's goals for an in-depth discussion of Carbon's vision for C++/Carbon interop and migration.

Why is adopting Rust difficult for C++ codebases?

Large existing C++ codebases almost certainly made architectural choices that are incompatible with safe Rust. Specifically:

  • Seamless interop where existing, unmodified C++ APIs are made callable from safe Rust requires the C++ code to follow borrow checking rules at the API boundary.
    • To reduce the amount of Rust-side compile-time checking that makes interop difficult, C++ APIs can be exposed to Rust with pointers instead of references. However, that forces users to write unsafe Rust, which can be even more tricky to write than C++ because it has new kinds of UB compared to C++; for example, stacked borrows violations.
  • Seamless interop where safe Rust APIs are made callable from C++ requires C++ users to follow Rust borrow checking rules.
  • Incremental migration of C++ to safe Rust means that C++ code gets converted to Rust without major changes to the architecture, data structures, or APIs. However Rust imposes stricter rules than C++, disallowing some design choices that were valid in C++. Therefore, the original C++ code must follow Rust rules before attempting a conversion.
    • Original C++ code must be structured in such a way that the resulting Rust code passes borrow checking. C++ APIs and data structures are not designed with this in mind.
    • Migrating C++ to unsafe Rust would still require the code to follow Rust's reference exclusivity and stacked borrows rules.

Why not a garbage collected language, like Java, Kotlin, or Go?

If you can use one of these languages, you absolutely should.

Garbage collection provides dramatically simpler memory management for developers, but at the expense of performance. The performance cost can range from direct runtime overhead to significant complexity and loss of control over performance. This trade-off makes sense for many applications, and we actively encourage using these languages in those cases. However, we need a solution for C++ use-cases that require its full performance, low-level control, and access to hardware.

How were specific feature designs chosen?

Throughout the design, we include 'Alternatives considered' and 'References' sections which can be used to research the decision process for a particular design.

Why aren't < and > used as delimiters?

One of our goals for Carbon is that it should support parsing without contextual or semantic information, and experience with C++ has shown that using < as both a binary operator and an opening delimiter makes that goal difficult to achieve.

For example, in C++, the expression a<b>(c) could parse as either a function call with a template argument b and an ordinary argument c, or as a chained comparison (a < b) > (c). In order to resolve the ambiguity, the compiler has to perform name lookup on a to determine whether there's a function named a in scope.

It's also worth noting that Carbon doesn't use any kind of brackets to mark template- or checked-generic parameters, so if Carbon had angle brackets, they would mean something different than they do in C++, which could cause confusion. We do use square brackets to mark deduced parameters, as in:

fn Sort[T:! Comparable](a: Vector(T)*)

But deduced parameters aren't the same thing as template parameters. In particular, deduced parameters are never mentioned at the callsite, so those square brackets are never part of the expression syntax.

See Proposal #676: :! generic syntax for more background on how and why we chose our current compile-time parameter syntax.

Why do variable declarations have to start with var or let?

In Carbon, a declaration of a single variable looks like this:

var the_answer: i32 = 42;

But this is just the most common case. The syntax between var and = can be any irrefutable pattern, not just a single variable binding. For example:

var ((x: i32, _: i32), y: auto) = ((1, 2), (3, 4));

This code is valid, and initializes x to 1 and y to (3, 4). In the future, we will probably also support destructuring structs in a similar way, and many other kinds of patterns are possible.

Now consider how that example would look if the var token were not required:

((x: i32, _: i32), y: auto) = ((1, 2), (3, 4));

With this example, the parser would need to look four tokens ahead to determine that it's parsing a variable declaration rather than an expression. With more deeply-nested patterns, it would have to look ahead farther. Avoiding this sort of unbounded lookahead is an important part of our fast and scalable development goal.

Why do variable declarations have to have types?

As discussed above, Carbon variable declarations are actually doing a form of pattern matching. In a declaration like this:

var the_answer: i32 = 42;

the_answer: i32 is an example of a binding pattern, which matches any value of the appropriate type, and binds the given name to it. The : i32 can't be omitted, because the_answer on its own is an expression, and any Carbon expression is also a valid pattern, which matches if the value being matched is equal to the value of the expression. So var the_answer = 42; would try to match 42 with the value of the expression the_answer, which requires a variable named the_answer to already exist.

There are other ways of approaching pattern matching, but there are tradeoffs. Pattern matching is still on a provisional design, and as of August 2022 it hasn't been fully reviewed with alternatives considered. A future proposal for pattern matching will need to weigh the tradeoffs in more detail, and may come to a different decision.

How will Carbon work?

What compiler infrastructure is Carbon using?

Carbon is being built using LLVM, and is expected to have Clang dependencies for interoperability.

How will Carbon's bidirectional C++ interoperability work?

The Carbon toolchain will compile both Carbon and C++ code together, in order to make the interoperability seamless.

For example, for import Cpp library "<vector>", Carbon will:

  • Call into Clang to load the AST of the vector header file.
  • Analyze the AST for public APIs, which will be turned into names that can be accessed from Carbon; for example, std::vector is Cpp.std.vector in Carbon.
  • Use Clang to instantiate the Cpp.std.vector template when parameterized references occur in Carbon code.
    • In other words, C++ templates will be instantiated using standard C++ mechanisms, and the instantiated versions are called by Carbon code.

Some code, such as #define preprocessor macros, will not work as well. C++ allows arbitrary content in a #define, and that can be difficult to translate. As a consequence, this is likely to be a limitation of interoperability and left to migration.

How do Carbon generics differ from templates?

Carbon's generic programming support will handle both templates (matching C++) and checked generics (common in other languages: Rust, Swift, Go, Kotlin, Java, and so on).

The key difference between the two is that template arguments can only finish type-checking during instantiation, whereas checked generics specify an interface with which arguments can finish type-checking without instantiation. This has a couple of important benefits:

  • Type-checking errors for checked generics happen earlier, making it easier for the compiler to produce helpful diagnostics.
  • Checked-generic functions can generate less compiled output, allowing compilation with many uses to be faster.
    • For comparison, template instantiations are a major factor for C++ compilation latency.

Although Carbon will prefer checked generics over templates, templates are provided for migration of C++ code.

References:

What is Carbon's memory model?

Carbon will match C++'s memory model closely in order to maintain zero-overhead interoperability. There may be some changes made as part of supporting memory safety, but performance and interoperability will constrain flexibility in this space.

How will Carbon achieve memory safety?

See memory safety in the project README.

References:

How will language version upgrades work?

Carbon will provide tooling to assist upgrades of code in response to language syntax changes, similar to C++ to Carbon migration tooling. For example, if a new keyword except is added in Carbon 1.1, an upgrade tool might be provided that would accept Carbon 1.0 code and replace except identifier uses with r#except raw identifiers (like Rust provides), automatically fixing the conflict.

While Carbon remains in early development, upgrade tooling is not ready. It is instead a consideration for declaring Carbon ready for use.

This upgrade approach stands in comparison to enforcing backwards or forwards compatibility.

How will the Carbon project work?

Where does development occur?

Carbon is using GitHub for its repository and code reviews. Most non-review discussion occurs on our Discord server.

If you're interested in contributing, you can find more information in our Contributing file.

How does Carbon make decisions?

Any interested developer may propose and discuss changes to Carbon. The Carbon leads are responsible for reviewing proposals and surrounding discussion, then making decisions based on the discussion. As Carbon grows, we expect to add feature teams to distribute responsibility.

The intent of this setup is that Carbon remains a community-driven project, avoiding situations where any single organization controls Carbon's direction.

References:

What happens when a decision was wrong?

Carbon's evolution process is iterative: when we make poor decisions, we'll work to fix them. If we realize a mistake quickly, it may make sense to just roll back the decision. Otherwise, a fix will need to follow the normal evolution process, with a proposal explaining why the decision was wrong and proposing a better path forward.

What license does Carbon use?

Carbon is under the Apache License v2.0 with LLVM Exceptions. We want Carbon to be available under a permissive open source license. As a programming language with compiler and runtime library considerations, our project has the same core needs as the LLVM project for its license and we build on their work to address these by combining the Apache License with the LLVM Exceptions.

Why make Carbon open source?

We believe it is important for a programming language like Carbon, if it is successful, to be developed by and for a broad community. We feel that the open source model is the most effective and successful approach for doing this. We're closely modeled on LLVM and other similar open source projects, and want to follow their good examples. We've structured the project to be attractive for industry players big and small to participate in, but also to be resilient and independent long-term.

The open source model, particularly as followed by Apache and LLVM, also provides a strong foundation for handling hard problems like intellectual property and licensing with a broad and diverse group of contributors.

Why does Carbon have a CLA?

Carbon uses a CLA (Contributor License Agreement) in case we need to fix issues with the license structure in the future, something which has proven to be important in other projects.

Any changes to the license of Carbon would be made very carefully and subject to the exact same decision making process as any other change to the overall project direction.

Initially, Carbon is bootstrapping using Google's CLA. We are planning to create an open source foundation and transfer all Carbon-related rights to it; our goal is for the foundation setup to be similar to other open source projects, such as LLVM or Kubernetes.

Who pays for Carbon's infrastructure?

Carbon is currently bootstrapping infrastructure with the help of Google. As soon as a foundation is ready to oversee infrastructure, such as continuous integration and the CLA, we plan to transfer them so they are run by the community.

How can I contribute to Carbon?

There are many ways to contribute, and we appreciate all of them. Begin by reading the project's Contributing page to learn more about how you can contribute.

What are the prerequisites for contributing to Carbon Language's design and tools?

Carbon Language isn't ready for use. This section is for people wishing to participate in designing and implementing the language.

Carbon is being designed to migrate C++ codebases and to look familiar to C++ programmers. As such, familiarity with C++ is very important. Carbon is also trying to learn from other programming languages, so having broad experience with other programming languages will be helpful to see tradeoffs in design decisions.

The Carbon toolchain is being implemented in C++, and we also use Python and Starlark. As we're building off of the LLVM project, familiarity with Clang and other parts of LLVM will be advantageous, but not required.

Our contribution tools page documents specific tools we use when building.

When do we revisit decisions or reopen discussions?

Once a decision is made through the evolution process the community should treat it as firmly decided. This doesn't mean that the decision is definitely right or set in stone, it just means we'd like the community to focus time and energy on other issues in the name of progress.

Sometimes, it will be appropriate to revisit a decision; for example, when there is new information introduced, a new community joins Carbon, or there is an order of magnitude growth in the community. These cases are handled as new proposals through the evolution process.

For example, we have done this with digit separators: we missed important domain conventions and had overly restricted where separators are allowed, an issue was filed with the new information, and we're fixing the choice.

See also the related questions What happens when a decision was wrong?, How does Carbon make decisions?, and What can I do if I disagree with a design decision?.

What can I do if I disagree with a design decision?

We invite you to give us constructive feedback. Some of Carbon's design decisions are made with the expectation of receiving community feedback. We understand that many decisions won't be universally popular, but we'd still like to understand the community's reaction to Carbon.

We encourage you to investigate why Carbon came to be the way it is. Designs will include links to the proposals and important alternatives considered that led to them, typically linked at the bottom. Read through and understand the context and rationale behind the decisions you are concerned about. You may find that your concerns were already thoroughly discussed. If not, you will be in a better place to present your thoughts in a convincing way.

Changing decisions that have come out of the evolution process involves a formal process. See When do we revisit decisions or reopen discussions?. For these issues in particular, please be aware that other community members may choose to not actively engage in detailed discussions, especially if the discussion seems to be revisiting points made in the past.

If after reading this answer you are not sure how to proceed please feel free to ask (see Where should I ask questions?).

How can I best say "I like X" or "I don't like X"?

Both Discord and GitHub Discussions allow you to give an emoji "reaction" to individual posts. If you'd like to amplify what has already been said, please use these instead of posting messages that re-state substantially the same thing. These make conversations easier to follow and understand general sentiment in discussions involving many people.