mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:50:14 +01:00
Remove : in variable declarations (#503)
Starting to apply #339 Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
committed by
GitHub
co-authored by
Richard Smith
parent
b1d11bae7e
commit
231264e0c0
+31
-31
@@ -164,7 +164,7 @@ package ExampleUser;
|
||||
|
||||
import Geometry library("OneSide");
|
||||
|
||||
fn Foo(var Geometry.Shapes.Flat.Circle: circle) { ... }
|
||||
fn Foo(Geometry.Shapes.Flat.Circle circle) { ... }
|
||||
```
|
||||
|
||||
### Names and scopes
|
||||
@@ -282,7 +282,7 @@ Some common expressions in Carbon include:
|
||||
Functions are the core unit of behavior. For example:
|
||||
|
||||
```carbon
|
||||
fn Sum(Int: a, Int: b) -> Int;
|
||||
fn Sum(Int a, Int b) -> Int;
|
||||
```
|
||||
|
||||
Breaking this apart:
|
||||
@@ -333,7 +333,7 @@ For example:
|
||||
|
||||
```carbon
|
||||
fn Foo() {
|
||||
var Int: x = 42;
|
||||
var Int x = 42;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -371,7 +371,7 @@ conditional execution of statements.
|
||||
For example:
|
||||
|
||||
```carbon
|
||||
fn Foo(Int: x) {
|
||||
fn Foo(Int x) {
|
||||
if (x < 42) {
|
||||
Bar();
|
||||
} else if (x > 77) {
|
||||
@@ -400,7 +400,7 @@ For example:
|
||||
|
||||
```carbon
|
||||
fn Foo() {
|
||||
var Int: x = 0;
|
||||
var Int x = 0;
|
||||
while (x < 42) {
|
||||
if (ShouldStop()) break;
|
||||
if (ShouldSkip(x)) {
|
||||
@@ -435,7 +435,7 @@ value is provided by an expression in the return statement. This allows us to
|
||||
complete the definition of our `Sum` function from earlier as:
|
||||
|
||||
```carbon
|
||||
fn Sum(Int: a, Int: b) -> Int {
|
||||
fn Sum(Int a, Int b) -> Int {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
@@ -502,7 +502,7 @@ tuple. In formal type theory, tuples are product types.
|
||||
An example use of tuples is:
|
||||
|
||||
```carbon
|
||||
fn DoubleBoth(Int: x, Int: y) -> (Int, Int) {
|
||||
fn DoubleBoth(Int x, Int y) -> (Int, Int) {
|
||||
return (2 * x, 2 * y);
|
||||
}
|
||||
```
|
||||
@@ -519,7 +519,7 @@ expression: one is a tuple of types, the other a tuple of values.
|
||||
Element access uses subscript syntax:
|
||||
|
||||
```carbon
|
||||
fn DoubleTuple((Int, Int): x) -> (Int, Int) {
|
||||
fn DoubleTuple((Int, Int) x) -> (Int, Int) {
|
||||
return (2 * x[0], 2 * x[1]);
|
||||
}
|
||||
```
|
||||
@@ -528,12 +528,12 @@ Tuples also support multiple indices and slicing to restructure tuple elements:
|
||||
|
||||
```carbon
|
||||
// This reverses the tuple using multiple indices.
|
||||
fn Reverse((Int, Int, Int): x) -> (Int, Int, Int) {
|
||||
fn Reverse((Int, Int, Int) x) -> (Int, Int, Int) {
|
||||
return x[2, 1, 0];
|
||||
}
|
||||
|
||||
// This slices the tuple by extracting elements [0, 2).
|
||||
fn RemoveLast((Int, Int, Int): x) -> (Int, Int) {
|
||||
fn RemoveLast((Int, Int, Int) x) -> (Int, Int) {
|
||||
return x[0 .. 2];
|
||||
}
|
||||
```
|
||||
@@ -565,11 +565,11 @@ For example:
|
||||
|
||||
```carbon
|
||||
struct Widget {
|
||||
var Int: x;
|
||||
var Int: y;
|
||||
var Int: z;
|
||||
var Int x;
|
||||
var Int y;
|
||||
var Int z;
|
||||
|
||||
var String: payload;
|
||||
var String payload;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -584,18 +584,18 @@ More advanced `struct`s may be created:
|
||||
```carbon
|
||||
struct AdvancedWidget {
|
||||
// Do a thing!
|
||||
fn DoSomething(AdvancedWidget: self, Int: x, Int: y);
|
||||
fn DoSomething(AdvancedWidget self, Int x, Int y);
|
||||
|
||||
// A nested type.
|
||||
struct Nestedtype {
|
||||
// ...
|
||||
}
|
||||
|
||||
private var Int: x;
|
||||
private var Int: y;
|
||||
private var Int x;
|
||||
private var Int y;
|
||||
}
|
||||
|
||||
fn Foo(AdvancedWidget: thing) {
|
||||
fn Foo(AdvancedWidget thing) {
|
||||
thing.DoSomething(1, 2);
|
||||
}
|
||||
```
|
||||
@@ -667,13 +667,13 @@ fn Bar() -> (Int, (Float, Float));
|
||||
|
||||
fn Foo() -> Float {
|
||||
match (Bar()...) {
|
||||
case (42, (Float: x, Float: y)) => {
|
||||
case (42, (Float x, Float y)) => {
|
||||
return x - y;
|
||||
}
|
||||
case (Int: p, (Float: x, Float: _)) if (p < 13) => {
|
||||
case (Int p, (Float x, Float _)) if (p < 13) => {
|
||||
return p * x;
|
||||
}
|
||||
case (Int: p, auto: _) if (p > 3) => {
|
||||
case (Int p, auto _) if (p > 3) => {
|
||||
return p * Pi;
|
||||
}
|
||||
default => {
|
||||
@@ -690,7 +690,7 @@ Breaking apart this `match`:
|
||||
- It then will find the _first_ `case` that matches this value, and
|
||||
execute that block.
|
||||
- If none match, then it executes the default block.
|
||||
- Each `case` pattern contains a value pattern, such as `(Int: p, auto: _)`,
|
||||
- Each `case` pattern contains a value pattern, such as `(Int p, auto _)`,
|
||||
followed by an optional boolean predicate introduced by the `if` keyword.
|
||||
- The value pattern must first match, and then the predicate must also
|
||||
evaluate to true for the overall `case` pattern to match.
|
||||
@@ -704,7 +704,7 @@ Value patterns may be composed of the following:
|
||||
- The special identifier `_` may be used to discard the value once
|
||||
matched.
|
||||
- A destructuring pattern containing a sequence of value patterns, such as
|
||||
`(Float: x, Float: y)`, which match against tuples and tuple-like values by
|
||||
`(Float x, Float y)`, which match against tuples and tuple-like values by
|
||||
recursively matching on their elements.
|
||||
- An unwrapping pattern containing a nested value pattern which matches
|
||||
against a variant or variant-like value by unwrapping it.
|
||||
@@ -724,7 +724,7 @@ An example use is:
|
||||
```carbon
|
||||
fn Bar() -> (Int, (Float, Float));
|
||||
fn Foo() -> Int {
|
||||
var (Int: p, auto: _) = Bar();
|
||||
var (Int p, auto _) = Bar();
|
||||
return p;
|
||||
}
|
||||
```
|
||||
@@ -733,7 +733,7 @@ To break this apart:
|
||||
|
||||
- The `Int` returned by `Bar()` matches and is bound to `p`, then returned.
|
||||
- The `(Float, Float)` returned by `Bar()` matches and is discarded by
|
||||
`auto: _`.
|
||||
`auto _`.
|
||||
|
||||
### Pattern matching as function overload resolution
|
||||
|
||||
@@ -775,10 +775,10 @@ be used to instantiate the parameterized definition with the provided arguments
|
||||
in order to produce a complete type. For example:
|
||||
|
||||
```carbon
|
||||
struct Stack(Type:$$ T) {
|
||||
var Array(T): storage;
|
||||
struct Stack(Type$$ T) {
|
||||
var Array(T) storage;
|
||||
|
||||
fn Push(T: value);
|
||||
fn Push(T value);
|
||||
fn Pop() -> T;
|
||||
}
|
||||
```
|
||||
@@ -805,12 +805,12 @@ arguments. The runtime call then passes the remaining arguments to the resulting
|
||||
complete definition.
|
||||
|
||||
```carbon
|
||||
fn Convert[Type:$$ T](T: source, Type:$$ U) -> U {
|
||||
var U: converted = source;
|
||||
fn Convert[Type$$ T](T source, Type$$ U) -> U {
|
||||
var U converted = source;
|
||||
return converted;
|
||||
}
|
||||
|
||||
fn Foo(Int: i) -> Float {
|
||||
fn Foo(Int i) -> Float {
|
||||
// Instantiates with the `T` implicit argument set to `Int` and the `U`
|
||||
// explicit argument set to `Float`, then calls with the runtime value `i`.
|
||||
return Convert(i, Float);
|
||||
|
||||
@@ -434,7 +434,7 @@ package Checksums library "Sha" api;
|
||||
|
||||
namespaces Sha256;
|
||||
|
||||
api fn Sha256.HexDigest(Bytes: data) -> String { ... }
|
||||
api fn Sha256.HexDigest(Bytes data) -> String { ... }
|
||||
```
|
||||
|
||||
Calling code may look like:
|
||||
@@ -444,9 +444,9 @@ package Caller api;
|
||||
|
||||
import Checksums library "Sha";
|
||||
|
||||
fn Process(Bytes: data) {
|
||||
fn Process(Bytes data) {
|
||||
...
|
||||
var String: digest = Checksums.Sha256.HexDigest(data);
|
||||
var String digest = Checksums.Sha256.HexDigest(data);
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -514,7 +514,7 @@ package Geometry api;
|
||||
import Geometry library "Shapes";
|
||||
|
||||
// Circle must be referenced using the Geometry namespace of the import.
|
||||
fn GetArea(Geometry.Circle: c) { ... }
|
||||
fn GetArea(Geometry.Circle c) { ... }
|
||||
```
|
||||
|
||||
### Namespaces
|
||||
@@ -801,7 +801,7 @@ syntax. For example:
|
||||
```carbon
|
||||
import Cpp file("myproject/myclass.h");
|
||||
|
||||
fn MyCarbonCall(var Cpp.MyProject.MyClass: x);
|
||||
fn MyCarbonCall(Cpp.MyProject.MyClass x);
|
||||
```
|
||||
|
||||
### Imports from URLs
|
||||
@@ -869,7 +869,7 @@ struct Quantiles {
|
||||
fn Stats();
|
||||
fn Build() {
|
||||
...
|
||||
var Math.Stats: b;
|
||||
var Math.Stats b;
|
||||
...
|
||||
}
|
||||
}
|
||||
@@ -1790,7 +1790,7 @@ example:
|
||||
import Geometry library "Shapes" names *;
|
||||
|
||||
// Triangle was imported as part of "*".
|
||||
fn Draw(var Triangle: x) { ... }
|
||||
fn Draw(Triangle x) { ... }
|
||||
```
|
||||
|
||||
Advantages:
|
||||
|
||||
@@ -41,7 +41,7 @@ control flow constructs are mostly similar to those in C, C++, and other
|
||||
languages.
|
||||
|
||||
```
|
||||
fn Foo(Int: x) {
|
||||
fn Foo(Int x) {
|
||||
if (x < 42) {
|
||||
Bar();
|
||||
} else if (x > 77) {
|
||||
@@ -60,7 +60,7 @@ an expression in the return statement. This allows us to complete the definition
|
||||
of our `Sum` function from earlier as:
|
||||
|
||||
```
|
||||
fn Sum(Int: a, Int: b) -> Int {
|
||||
fn Sum(Int a, Int b) -> Int {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@ primarily divided up into "functions" (or "procedures", "subroutines", or
|
||||
language. Let's look at a simple example to understand how these work:
|
||||
|
||||
```
|
||||
fn Sum(Int: a, Int: b) -> Int;
|
||||
fn Sum(Int a, Int b) -> Int;
|
||||
```
|
||||
|
||||
This declares a function called `Sum` which accepts two `Int` parameters, the
|
||||
@@ -47,7 +47,7 @@ auto Sum(std::int64_t a, std::int64_t b) -> std::int64_t;
|
||||
Let's look at how some specific parts of this work. The function declaration is
|
||||
introduced with a keyword `fn` followed by the name of the function `Sum`. This
|
||||
declares that name in the surrounding scope and opens up a new scope for this
|
||||
function. We declare the first parameter as `Int: a`. The `Int` part is an
|
||||
function. We declare the first parameter as `Int a`. The `Int` part is an
|
||||
expression (here referring to a constant) that computes the type of the
|
||||
parameter. The `:` marks the end of the type expression and introduces the
|
||||
identifier for the parameter, `a`. The parameter names are introduced into the
|
||||
|
||||
@@ -440,8 +440,8 @@ Disadvantages:
|
||||
Advantages:
|
||||
|
||||
- Simpler, more flexible rule, that may allow some groupings that are
|
||||
conventional in a specific domain. For example, `var Date: d = 01_12_1983;`,
|
||||
or `var Int64: time_in_microseconds = 123456_000000;`.
|
||||
conventional in a specific domain. For example, `var Date d = 01_12_1983;`,
|
||||
or `var Int64 time_in_microseconds = 123456_000000;`.
|
||||
- Culturally agnostic. For example, the Indian convention for digit separators
|
||||
would group the last three digits, and then every two digits before that
|
||||
(1,23,45,678 could be written `1_23_45_678`).
|
||||
@@ -466,7 +466,7 @@ Disadvantages:
|
||||
be desirable. For example:
|
||||
|
||||
```carbon
|
||||
var Float32: flt_max =
|
||||
var Float32 flt_max =
|
||||
BitCast(Float32, 0b0_11111110_11111111111111111111111);
|
||||
```
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Foo {
|
||||
}
|
||||
}
|
||||
|
||||
fn F(Foo.Bar.MyInt: x);
|
||||
fn F(Foo.Bar.MyInt x);
|
||||
```
|
||||
|
||||
Carbon packages are also namespaces so to get to an imported name from the
|
||||
|
||||
@@ -47,13 +47,13 @@ under active investigation for C++. Carbon's `match` can be used as follows:
|
||||
fn Bar() -> (Int, (Float, Float));
|
||||
fn Foo() -> Float {
|
||||
match (Bar()) {
|
||||
case (42, (Float: x, Float: y)) => {
|
||||
case (42, (Float x, Float y)) => {
|
||||
return x - y;
|
||||
}
|
||||
case (Int: p, (Float: x, Float: _)) if (p < 13) => {
|
||||
case (Int p, (Float x, Float _)) if (p < 13) => {
|
||||
return p * x;
|
||||
}
|
||||
case (Int: p, auto: _) if (p > 3) => {
|
||||
case (Int p, auto _) if (p > 3) => {
|
||||
return p * Pi;
|
||||
}
|
||||
default => {
|
||||
@@ -70,7 +70,7 @@ value, and execute that block. If none match, then it executes the default
|
||||
block.
|
||||
|
||||
Each `case` contains a pattern. The first part is a value pattern
|
||||
(`(Int: p, auto: _)` for example) followed by an optional boolean predicate
|
||||
(`(Int p, auto _)` for example) followed by an optional boolean predicate
|
||||
introduced by the `if` keyword. The value pattern has to match, and then the
|
||||
predicate has to evaluate to true for the overall pattern to match. Value
|
||||
patterns can be composed of the following:
|
||||
@@ -80,14 +80,13 @@ patterns can be composed of the following:
|
||||
identifier to bind to the value or the special identifier `_` to discard the
|
||||
value once matched.
|
||||
- A destructuring pattern containing a sequence of value patterns
|
||||
(`(Float: x, Float: y)`) which match against tuples and tuple like values by
|
||||
(`(Float x, Float y)`) which match against tuples and tuple like values by
|
||||
recursively matching on their elements.
|
||||
- An unwrapping pattern containing a nested value pattern which matches
|
||||
against a variant or variant-like value by unwrapping it.
|
||||
|
||||
In order to match a value, whatever is specified in the pattern must match.
|
||||
Using `auto` for a type will always match, making `auto: _` the wildcard
|
||||
pattern.
|
||||
Using `auto` for a type will always match, making `auto _` the wildcard pattern.
|
||||
|
||||
### Pattern matching in local variables
|
||||
|
||||
@@ -99,7 +98,7 @@ directly.
|
||||
```
|
||||
fn Bar() -> (Int, (Float, Float));
|
||||
fn Foo() -> Int {
|
||||
var (Int: p, auto: _) = Bar();
|
||||
var (Int p, auto _) = Bar();
|
||||
return p;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -36,11 +36,11 @@ structuring data:
|
||||
|
||||
```
|
||||
struct Widget {
|
||||
var Int: x;
|
||||
var Int: y;
|
||||
var Int: z;
|
||||
var Int x;
|
||||
var Int y;
|
||||
var Int z;
|
||||
|
||||
var String: payload;
|
||||
var String payload;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -50,18 +50,18 @@ often using different syntax:
|
||||
```
|
||||
struct AdvancedWidget {
|
||||
// Do a thing!
|
||||
fn DoSomething(AdvancedWidget: self, Int: x, Int: y);
|
||||
fn DoSomething(AdvancedWidget self, Int x, Int y);
|
||||
|
||||
// A nested type.
|
||||
struct NestedType {
|
||||
// ...
|
||||
}
|
||||
|
||||
private var Int: x;
|
||||
private var Int: y;
|
||||
private var Int x;
|
||||
private var Int y;
|
||||
}
|
||||
|
||||
fn Foo(AdvancedWidget: thing) {
|
||||
fn Foo(AdvancedWidget thing) {
|
||||
thing.DoSomething(1, 2);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -26,7 +26,7 @@ update as appropriate.
|
||||
|
||||
## Overview
|
||||
|
||||
Right now we expect variable syntax like: `Int: x`.
|
||||
Right now we expect variable syntax like: `Int x`.
|
||||
|
||||
There are probably other syntactic conventions that can be added here, too.
|
||||
|
||||
@@ -45,7 +45,7 @@ One very important consideration here is the fundamental approach to type
|
||||
inference. Languages which use the syntax `<identifier>: <type>` typically allow
|
||||
completely omitting the colon and the type to signify inference. With C++,
|
||||
inference is achieved with a placeholder keyword `auto`, and Carbon is currently
|
||||
being consistent there as well with `auto: <identifier>`. For languages which
|
||||
being consistent there as well with `auto <identifier>`. For languages which
|
||||
simply allow omission, this seems an intentional incentive to encourage
|
||||
inference. On the other hand, there has been strong advocacy in the C++
|
||||
community to not overly rely on inference and to write the explicit type
|
||||
|
||||
@@ -44,10 +44,10 @@ are subject to full instantiation -- other parameters will be type checked and
|
||||
bound early to the extent possible. For example:
|
||||
|
||||
```
|
||||
struct Stack(Type:$$ T) {
|
||||
var Array(T): storage;
|
||||
struct Stack(Type$$ T) {
|
||||
var Array(T) storage;
|
||||
|
||||
fn Push(T: value);
|
||||
fn Push(T value);
|
||||
fn Pop() -> T;
|
||||
}
|
||||
```
|
||||
@@ -67,12 +67,12 @@ arguments. The runtime call then passes the remaining arguments to the resulting
|
||||
complete definition.
|
||||
|
||||
```
|
||||
fn Convert[Type:$$ T](T: source, Type:$$ U) -> U {
|
||||
var U: converted = source;
|
||||
fn Convert[Type$$ T](T source, Type$$ U) -> U {
|
||||
var U converted = source;
|
||||
return converted;
|
||||
}
|
||||
|
||||
fn Foo(Int: i) -> Float {
|
||||
fn Foo(Int i) -> Float {
|
||||
// Instantiates with the `T` implicit argument set to `Int` and the `U`
|
||||
// explicit argument set to `Float`, then calls with the runtime value `i`.
|
||||
return Convert(i, Float);
|
||||
|
||||
@@ -34,7 +34,7 @@ The primary composite type involves simple aggregation of other types as a tuple
|
||||
(called a "product type" in formal type theory):
|
||||
|
||||
```
|
||||
fn DoubleBoth(Int: x, Int: y) -> (Int, Int) {
|
||||
fn DoubleBoth(Int x, Int y) -> (Int, Int) {
|
||||
return (2 * x, 2 * y);
|
||||
}
|
||||
```
|
||||
@@ -50,8 +50,8 @@ of types.
|
||||
Element access uses subscript syntax:
|
||||
|
||||
```
|
||||
fn Bar(Int: x, Int: y) -> Int {
|
||||
var (Int, Int): t = (x, y);
|
||||
fn Bar(Int x, Int y) -> Int {
|
||||
var (Int, Int) t = (x, y);
|
||||
return t[0] + t[1];
|
||||
}
|
||||
```
|
||||
@@ -59,9 +59,9 @@ fn Bar(Int: x, Int: y) -> Int {
|
||||
Tuples also support multiple indices and slicing to restructure tuple elements:
|
||||
|
||||
```
|
||||
fn Baz(Int: x, Int: y, Int: z) -> (Int, Int) {
|
||||
var (Int, Int, Int): t1 = (x, y, z);
|
||||
var (Int, Int, Int): t2 = t1[(2, 1, 0)];
|
||||
fn Baz(Int x, Int y, Int z) -> (Int, Int) {
|
||||
var (Int, Int, Int) t1 = (x, y, z);
|
||||
var (Int, Int, Int) t2 = t1[(2, 1, 0)];
|
||||
return t2[0 .. 2];
|
||||
}
|
||||
```
|
||||
|
||||
@@ -35,7 +35,7 @@ For example:
|
||||
|
||||
```
|
||||
fn Foo() {
|
||||
var Int: x = 42;
|
||||
var Int x = 42;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ Constants will use template-like syntax for declarations. For example, a simple
|
||||
integer constant looks like:
|
||||
|
||||
```carbon
|
||||
var Int:$$ MyVal = 42;
|
||||
var Int$$ MyVal = 42;
|
||||
```
|
||||
|
||||
## Alternatives
|
||||
|
||||
Reference in New Issue
Block a user