You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Here is the new Carbon Copy, your periodic update on the Carbon language!
Carbon Copy is designed for those people who want a high-level view of what's happening on the project. If you'd like to subscribe, you can join [email protected]. Carbon Copy should arrive roughly (sometimes very roughly) every other month.
Toolchain Progress
If you don't want to compile the toolchain yourself, Carbon is now releasing nightly builds. Instructions are on the homepage; in short:
# A variable with the specific nightly version:
VERSION="$(date -d yesterday +0.0.0-0.nightly.%Y.%m.%d)"
# Get the release
wget https:/carbon-language/carbon-lang/releases/download/v${VERSION}/carbon_toolchain-${VERSION}.tar.gz
# Unpack the toolchain:
tar -xvf carbon_toolchain-${VERSION}.tar.gz
# Create a simple Carbon source file:
echo "fn Run() { Core.Print(42); }" > forty_two.carbon
# Compile to an object file:
./carbon_toolchain-${VERSION}/bin/carbon compile \
--output=forty_two.o forty_two.carbon
# Install minimal system libraries used for linking. Note that installing `gcc`
# or `g++` for compiling C/C++ code with GCC will also be sufficient, these are
# just the specific system libraries Carbon linking still uses.
# sudo apt install libgcc-11-dev
# Link to an executable:
./carbon_toolchain-${VERSION}/bin/carbon link \
--output=forty_two forty_two.o
# Run it:
./forty_two
This toolchain is not ready for actual use. Visit our releases page for your nightly experiments!
Spotlight: Pattern matching and tuples
This issue, we're going to look at patterns. A design goal for Carbon is to have a single kind of pattern matching all across the language. This language is used in places like:
name-binding declarations
function parameters
match statements
Each of these look similar, as they use subsets of the features of Carbons patterns. This spotlight will dig into each of these three uses of patterns. Along the way, we're going to explore Carbon's implementation of tuples for the examples.
Let's get started!
Tuples
So, how about tuples? Tuples are a composite type that can contain an arbitrary number of values, which in turn can also be tuples. To declare the type of a tuple, you can create a tuple of types.
let a_tuple: (i32, bool) = (4, true);
// Note that tuple literals can have trailing commas
let a_tuple: auto = (0.5, false,);
// In fact, single-element tuples require trailing commas to
// disambiguate grouping parentheses.
// This is an integer
let x: auto = (1 + 2);
// This is a 1-tuple
let y: auto = (1 + 2,);
// Tuples can be 0-element
let empty_tuple: auto = ();
// Or arbitrarily deep.
let nested_tuple: (i32, (f32, bool)) = (2, (3.0, true));
A pattern is an expression-like syntax that describes the structure of some value.
Patterns are allowed to have unknowns which may have names. These are called binding patterns, and similar such features appear in other languages. When a pattern is given a value (called the scrutinee), the pattern determines whether the scrutinee matches the pattern, and if so, determines the values of the bindings.
Here are some tuple binding patterns:
// This binds `a` to `a_tuple.0` and `b` to `a_tuple.1`
let (a: i32, b: bool) = a_tuple;
This will be reminiscent of C++ structured binding declarations. However, unlike C++ structured binding declarations, Carbon patterns let you specify the types of the individual bindings, and Carbon tuple patterns can be nested:
// Given existing variables a, b, c, d, e, and f
var (a_prime: auto, (b_prime: auto, c_prime: auto, d_prime: auto)) = (a, (b, c, (d, e, f)))
// a_prime == a
// b_prime == b
// c_prime == c
// d_prime == (d, e, f)
// Underscore (`_`) indicates "don't care"; you can use it more than once
let (first: bool, _: bool, third: bool, _:bool) = a_long_tuple;
You can also pattern match on structs.
let a_struct: auto = {.a = 1 as i32, .b = 2.0 as f32, .c as f32};
// This initializes x to a_struct.a and y to a_struct.b.
let {.a = x: i32, .b = y: f32, .c = z: f32} = a_struct;
// When the variable name is the same as the field name, you can use a
// shorthand, and you don't need to use every field:
let {a: i32, b: f32, _} = a_struct;
let an_int: i32 = 2;
# a var declaration is short for "let var..."
var an_int_var: i32 = 2;
These two cases are different.
an_int is a value. It provides 2 when accessed, and is immutable. It may or may not be implemented as a copy or a reference, but that is transparent to its user.
an_int_var is a variable, which means it has explicit storage allocated to it and is mutable. Every var has its own storage and doesn't affect other variables.
an_int: i32 and an_int_var: i32 are trivial binding patterns that bind a single unknown to a single scrutinee.
var is actually a pattern operator, and when it's used to introduce a statement, it's a shorthand for let var. var available in any pattern context, including tuple patterns. var makes a mutable copy of the scrutinee, and then matches that copy against the operand of var. All binding patterns nested under a var pattern define variables rather than values.
// q is a variable, p and r are values
let (p: i32, (var q: f32, r: bool)) = nested_tuple;
// q and r are both variables, and deep copies of parts of nested_tuple
let (p: i32, var (q: f32, r: bool)) = nested_tuple;
Function signatures
In Carbon, function signatures look like this:
fn F(a: i32, b: bool);
fn DoSomething(arg: i32);
You might notice that this looks familiar. Function signatures are patterns. A toplevel function signature has to be a tuple pattern.
Side note: You might remember from above that single-element tuple literals require a trailing comma to avoid an ambiguity with grouping parentheses. In a function signature, there is no ambiguity, so a trailing comma is not required.
And var can make an appearance in function signatures, too, doing what you'd expect:
fn F(a: i32, var mutable_copy_b: bool);
match and patterns
In C++ you can use a switch statement to execute different code depending on which of several values a given expression has. Carbon's match statement is similar:
match (a) {
case 5 => { DoSomething(); }
case 9 => { DoSomethingElse(); }
default => { DoSomethingDefault(); }
}
Carbon's match is more general than switch. Unlike C++, the cases can be patterns, with all the features we introduced above. Furthermore, the patterns can be refutable, meaning they don't have to match all possible values: if one case doesn't match the scrutinee, the match statement will just move on to the next one.
match (a_tuple) {
case (1, _: auto) => {
// This block runs if `a_tuple == (1, [anything])`.
}
case (x: i32, false) => {
// This block runs if `a_tuple.1 == false`. `x` is bound to `a_tuple.0`.
// It does not run if a_tuple.0 == 1, as the first case will match before
// reaching this case.
}
case (x: i32, y: bool) => {
// The first case that matches will be run, so this block runs if
// `a_tuple.1 == true and a_tuple.0 != 1`.
}
}
This last example gets a little outside of this topic, as it uses templates, but it's also a neat outcome of the consistency of using patterns. (Generics will be the topic of future spotlights. There's so much to talk about!) In this example (which contains speculative features), the case executed is determined by the type of x, not its value:
Carbon uses pattern features and syntax across the language, from local variables to function signatures to match/case statements. In C++ these each of these three different features have their own rules.
By treating them as aspects of a single concept in Carbon, we intend to give programmers fewer differences and distinctions to learn and remember. This consistency can even help with tasks like refactoring code; switching from a match statement to an overloaded function should be very straightforward. Pattern concepts like var are the same in function definitions and match and in let.
If you want more current discussion, check out the weekly meeting notes from the Carbon Weekly Sync. Please see the archive for notes from earlier weeks and months.
Wrap-up
Don't forget to subscribe! You can join [email protected]. If you have comments or would like to contribute to future editions of Carbon Copy, please reach out. And, always, join us any way you can!
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Carbon Copy, September 2024
Here is the new Carbon Copy, your periodic update on the Carbon language!
Carbon Copy is designed for those people who want a high-level view of what's happening on the project. If you'd like to subscribe, you can join [email protected]. Carbon Copy should arrive roughly (sometimes very roughly) every other month.
Toolchain Progress
If you don't want to compile the toolchain yourself, Carbon is now releasing nightly builds. Instructions are on the homepage; in short:
This toolchain is not ready for actual use. Visit our releases page for your nightly experiments!
Spotlight: Pattern matching and tuples
This issue, we're going to look at patterns. A design goal for Carbon is to have a single kind of pattern matching all across the language. This language is used in places like:
Each of these look similar, as they use subsets of the features of Carbons patterns. This spotlight will dig into each of these three uses of patterns. Along the way, we're going to explore Carbon's implementation of tuples for the examples.
Let's get started!
Tuples
So, how about tuples? Tuples are a composite type that can contain an arbitrary number of values, which in turn can also be tuples. To declare the type of a tuple, you can create a tuple of types.
To index into a tuple, you can index with a constant expression.
Tuples are used to return more than one value:
Patterns
A pattern is an expression-like syntax that describes the structure of some value.
Patterns are allowed to have unknowns which may have names. These are called binding patterns, and similar such features appear in other languages. When a pattern is given a value (called the scrutinee), the pattern determines whether the scrutinee matches the pattern, and if so, determines the values of the bindings.
Here are some tuple binding patterns:
This will be reminiscent of C++ structured binding declarations. However, unlike C++ structured binding declarations, Carbon patterns let you specify the types of the individual bindings, and Carbon tuple patterns can be nested:
You can also pattern match on structs.
Patterns and
var
In the previous Spotlight we discussed name-binding declarations.
These two cases are different.
an_int
is a value. It provides2
when accessed, and is immutable. It may or may not be implemented as a copy or a reference, but that is transparent to its user.an_int_var
is a variable, which means it has explicit storage allocated to it and is mutable. Everyvar
has its own storage and doesn't affect other variables.an_int: i32
andan_int_var: i32
are trivial binding patterns that bind a single unknown to a single scrutinee.var
is actually a pattern operator, and when it's used to introduce a statement, it's a shorthand forlet var
.var
available in any pattern context, including tuple patterns.var
makes a mutable copy of the scrutinee, and then matches that copy against the operand ofvar
. All binding patterns nested under avar
pattern define variables rather than values.Function signatures
In Carbon, function signatures look like this:
You might notice that this looks familiar. Function signatures are patterns. A toplevel function signature has to be a tuple pattern.
Side note: You might remember from above that single-element tuple literals require a trailing comma to avoid an ambiguity with grouping parentheses. In a function signature, there is no ambiguity, so a trailing comma is not required.
And
var
can make an appearance in function signatures, too, doing what you'd expect:match and patterns
In C++ you can use a
switch
statement to execute different code depending on which of several values a given expression has. Carbon'smatch
statement is similar:Carbon's
match
is more general thanswitch
. Unlike C++, the cases can be patterns, with all the features we introduced above. Furthermore, the patterns can be refutable, meaning they don't have to match all possible values: if onecase
doesn't match the scrutinee, thematch
statement will just move on to the next one.This last example gets a little outside of this topic, as it uses templates, but it's also a neat outcome of the consistency of using patterns. (Generics will be the topic of future spotlights. There's so much to talk about!) In this example (which contains speculative features), the case executed is determined by the type of
x
, not its value:Conclusion
Why do we think patterns are so important?
Carbon uses pattern features and syntax across the language, from local variables to function signatures to match/case statements. In C++ these each of these three different features have their own rules.
By treating them as aspects of a single concept in Carbon, we intend to give programmers fewer differences and distinctions to learn and remember. This consistency can even help with tasks like refactoring code; switching from a match statement to an overloaded function should be very straightforward. Pattern concepts like
var
are the same in function definitions andmatch
and inlet
.Read more about patterns (with footnotes!) in our toplevel design doc.
Recent proposals
In progress since last newsletter, now approved & merged:
New since last newsletter, now approved & merged:
Carbon at Conferences
Recently
Upcoming
Other notes
If you want more current discussion, check out the weekly meeting notes from the Carbon Weekly Sync. Please see the archive for notes from earlier weeks and months.
Wrap-up
Don't forget to subscribe! You can join [email protected]. If you have comments or would like to contribute to future editions of Carbon Copy, please reach out. And, always, join us any way you can!
Isotopically yours,
Geoffrey, Josh, Wolff, and the Carbon team
Beta Was this translation helpful? Give feedback.
All reactions