Remove : in variable declarations (#503)

Starting to apply #339

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Jon Meow
2021-05-17 15:24:20 -07:00
committed by GitHub
co-authored by Richard Smith
parent b1d11bae7e
commit 231264e0c0
12 changed files with 77 additions and 78 deletions
+31 -31
View File
@@ -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:
+2 -2
View File
@@ -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;
}
```
+2 -2
View File
@@ -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);
```
+1 -1
View File
@@ -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
+7 -8
View File
@@ -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;
}
```
+8 -8
View File
@@ -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);
}
```
+2 -2
View File
@@ -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
+6 -6
View File
@@ -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);
+6 -6
View File
@@ -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];
}
```
+2 -2
View File
@@ -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