# Declarations and aliases
## Unified declarations
All Cpp2 declarations are written as **"_name_ `:` _kind_ `=` _statement_"**.
- The _name_ must be a valid identifier (start with a letter, and consist of letters, digits, or `_`). The name can be variadic (be a name for a list of zero or more things) by writing a `...` suffix at the end of the name.
- The `:` is pronounced **"is a."**
- The _kind_ can start with [template parameters](#template-parameters) and end with [`#!cpp requires` constraints](#requires).
- The `=` is pronounced **"defined as."** For the definition of something that will always have the same value, write `==`, pronounced **"defined as a synonym for"**.
- The _statement_ is typically an expression statement (e.g., `#!cpp a + b();`) or a compound statement (e.g., `#!cpp { /*...*/ return c(d) / e; }`).
Various parts of the syntax allow a `_` "don't care" wildcard or can be omitted entirely to accept a default (e.g., `#!cpp x: int = 0;` can be equivalently written `#!cpp x: _ = 0;` or `#!cpp x := 0;` both of which deduce the type).
> Notes:
>
> - When the type is omitted, whitespace does not matter, and writing `#!cpp x: = 0;` or `#!cpp x : = 0;` or `#!cpp x := 0;` or other whitespace is just a stylistic choice. This documentation's style uses the last one, except when there are multiple adjacent declaration lines this style lines up their `:` and `=`.
>
> - `==` stresses that this name will always have the given value, to express [aliases](#aliases) and side-effect-free 'constexpr' [function aliases](#function-aliases).
### Unnamed declaration expressions
In an expression, most declarations can be written without a name (just starting with `:`). Such unnamed declaration expressions are useful for single-use temporary variables or 'lambda' functions that don't need a name to be reused elsewhere. For example:
- `#!cpp :widget = 42` is an unnamed expression-local (aka temporary) object of type `widget` defined as having the initial value `#!cpp 42`. It uses the same general syntax, just without declaring a name.
- `#!cpp :(x) = std::cout anonymous function (aka 'lambda')
:(x: int = init) = { /*...*/ } // x is a parameter to the function
:(x: int = init) = statement; // same, except return type is deduced
// Omit declaration => local and immediate (aka 'let' in other languages)
(x: int = init) { /*...*/ } // x is a parameter to this
(x: int = init) statement; // compound or single-statement
// Omit parameters => ordinary block or statement
{ /*...*/ } // ordinary compound statement
statement; // ordinary statement
```
Conversely, we can start with an ordinary block or statement, and successively build it up to make it more powerful:
``` cpp title="Start with an ordinary block or statement, and successively add parts" hl_lines="1 5 9 13"
// Ordinary block or statement
{ /*...*/ } // ordinary compound statement
statement; // ordinary statement
// Add parameters => more RAII locally-scoped variables
(x: int = init) { /*...*/ } // x is destroyed after this
(x: int = init) statement; // compound or single-statement
// Add declaration => treat the code as a callable object
:(x: int = init) = { /*...*/ } // x is a parameter to the function
:(x: int = init) = statement; // same, except return type is deduced
// Add name => full named function
f:(x: int = init) = { /*...*/ } // x is a parameter to the function
f:(x: int = init) = statement; // same, except return type is deduced
```
### Template parameters
A template parameter list is a [list](common.md#lists) enclosed by `` angle brackets, and the parameters separated by commas. Each parameter is declared using the [same syntax as any type or object](declarations.md). If a parameter's **`:`** ***kind*** is not specified, the default is `: type`.
For example:
``` cpp title="Declaring template parameters" hl_lines="1-3 8-9"
array: type
// parameter T is a type
// parameter size is a 32-bit int
= {
// ...
}
tuple: type
// parameter Ts is variadic list of zero or more types
= {
// ...
}
```
### `#!cpp requires` constraints
A `#!cpp requires` ***condition*** constraint appears at the end of the ***kind*** of a templated declaration. If the condition evaluates to `#!cpp false`, that specialization of the template is ignored as if not declared.
For example:
``` cpp title="A requires constraint on a variadic function" hl_lines="3"
print:
(inout out: std::ostream, args...: Args)
requires sizeof...(Args) >= 1u
= {
(out bool
= {
// pen is an object of deduced (omitted) type 'color',
// defined as having initial value 'color::red'
pen := color::red;
// success is an object of deduced (omitted) type bool,
// defined as having initial value 'false'
success := false;
// ...
return success;
}
// count is a function taking 'this' and returning a type
// deduced from its body, defined as a single-expression body
// (equivalent to '= { return points.ssize(); }' but omitting
// syntax where we're using the language defaults)
count: (this) -> _ = points.ssize();
// ...
}
// color is an @enum type (see Note) defined as having these enumerators
color: @enum type = { red; green; blue; }
// calc_next_year is a function defined as always returning the same
// value for the same input (i.e., 'constexpr', side effect-free)
calc_next_year: (year: i32) -> i32 == year + 1;
}
```
> Note: `@enum` is a metafunction, which provides an easy way to opt into a group of defaults, constraints, and generated functions. For details, see [`@enum`](metafunctions.md#enum).
## Aliases
Aliases are pronounced **"synonym for"**, and written using the same **name `:` kind `=` value** [declaration syntax](../cpp2/declarations.md) as everything in Cpp2:
- **name** is declared to be a synonym for **value**.
- **kind** can be any of the kinds: `namespace`, `type`, a function signature, or a type.
- **`==`**, pronounced **"defined as a synonym for"**, always precedes the value. The `==` syntax stresses that during compilation every use of the name could be equivalently replaced with the value.
- **value** is the expression that the **name** is a synonym for.
### Namespace aliases
A namespace alias is written the same way as a [namespace](namespaces.md), but using `==` and with the name of another namespace as its value. For example:
``` cpp title="Namespace aliases" hl_lines="1 2 4 5 8 12 16"
// 'chr' is a namespace defined as a synonym for 'std::chrono'
chr : namespace == std::chrono;
// 'chrlit' is a namespace defined as a synonym for 'std::chrono_literals'
chrlit : namespace == std::chrono_literals;
main: () = {
using chrlit::_ ;
// The next two lines are equivalent
std::cout );
}
```
### Function aliases
A function alias is written the same way as a [function](functions.md), but using `==` and with a side-effect-free body as its value; the body must always return the same value for the same input arguments. For example:
``` cpp title="Function aliases" hl_lines="1 2 6 9 12 15"
// 'square' is a function defined as a synonym for the value of 'i * i'
square: (i: i32) -> _ == i * i;
main: () = {
// It can be used at compile time, with compile time values
ints: std::array = ();
// Assertion that the size is the square of 4
static_assert( ints.size() == 16 );
// And it can be used at run time, with run time values
std::cout Note: A function alias is compiled to a Cpp1 `#!cpp constexpr` function.
### Object aliases
An object alias is written the same way as an [object](objects.md), but using `==` and with a side-effect-free value. For example:
``` cpp title="Function aliases" hl_lines="1 2 5 6"
// 'BufferSize' is an object defined as a synonym for the value 1'000'000
BufferSize: i32 == 1'000'000;
main: () = {
buf: std::array = ();
static_assert( buf.size() == BufferSize );
}
```
> Note: An object alias is compiled to a Cpp1 `#!cpp constexpr` object.