# Common programming concepts ## `main` As always, `main` is the entry point of the program. For example: `main` can have either: - No parameters:   **`#!cpp main: () /*etc.*/`** - One parameter of implicit type named `args`:   **`#!cpp main: (args) /*etc.*/`** - The type of `args` cannot be explicitly specified. It is always `cpp2::args_t`, which behaves similarly to a `#!cpp const std::array`. - Using `args` performs zero heap allocations. Every `string_view` is directly bound to the string storage provided by host environment. - `args.argc` and `args.argv` additionally provide access to the raw C/C++ `main` parameters. ``` cpp title="main with (args)" hl_lines="5 9" // Print out command line arguments, then invoke // a Qt event loop for a non-UI Qt application main: (args) -> int = { for args do (arg) { std::cout << arg << "\n"; } app: QCoreApplication = (args.argc, args.argv); return app.exec(); } ``` `main` can return: - `#!cpp void`, the default return value for functions. No `#!cpp return` statement is allowed in the body. In this case, the compiled Cpp1 code behaves as if `main` returned `#!cpp int`. - `#!cpp int`. If the body has no `#!cpp return` statement, the default is to `#!cpp return 0;` at the end of the function body. - Some other type that your Cpp1 compiler(s) supports as a nonstandard extension. ## Comments The usual `#!cpp // line comments` and `#!cpp /* stream comments */` are supported. For example: ``` cpp title="Writing comments" // A line comment: After //, the entire // rest of the line is part of the comment /* A stream comment: After /*, everything until the next * / (without a space between) is part of the comment. Note that stream comments do not nest. */ ``` ## Lists and commas All lists use `,` commas between list items, and may be enclosed by - `(` `)` parentheses, for most lists - `[` `]` brackets, for calling the subscript operator - `<` `>` angle brackets, for template parameter/argument lists For example: ``` cpp title="Lists" hl_lines="1 4 6 7" print: (t: T, u: U) = { std::cout << t << u << "\n"; } main: () = { array: std::array = ('A', 'B', 'C'); for (0, 1, 2) do (e) { print( e, array[e] ); } // Prints: // 0A // 1B // 2C } ``` An extra comma at the end of the list, before the closing `)` or `>`, is always allowed but ignored if present (for details, see [Design note: Commas](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Commas)). For example: ``` cpp title="Lists, using optional trailing commas just because we can" hl_lines="1 4 6 7" print: (t: T, u: U,) = { std::cout << t << u << "\n"; } main: () = { array: std::array = ('A', 'B', 'C',); for (0, 1, 2,) do (e) { print( e, array[e,], ); } // Prints: // 0A // 1B // 2C } ``` ## Contextual keywords Cpp2 has very few globally reserved keywords; nearly all keywords are contextual, where they have their special meaning when they appear in a particular place in the grammar. For example: - `new` is used as an ordinary function to do allocation (e.g., `shared.new(1, 2, 3)`). - `struct` and `enum` are used as function names in the metafunctions library. - `type` can be used as an ordinary name (e.g., `std::common_type::type`). - Unqualified `type_of(x)` is a synonym for Cpp1 `std::remove_cvref_t`. In rare cases, usually when consuming code written in other languages, you may need to write a name that is a reserved keyword. The way to do that is to prefix it with `__identifer__`, which treats it as an ordinary identifier (without the prefix). ## Fundamental data types Cpp2 supports the same fundamental types as today's Cpp1, but additionally provides the following aliases in namespace `cpp2`: | Fixed-width types | Synonym for | |---|---| | `i8` | `std::int8_t` | | `i16` | `std::int16_t` | | `i32` | `std::int32_t` | | `i64` | `std::int64_t` | | `u8` | `std::uint8_t` | | `u16` | `std::uint16_t` | | `u32` | `std::uint32_t` | | `u64` | `std::uint64_t` | | Variable-width types
(Cpp2-compatible single-word names) | Synonym for (these multi-word
names are not allowed in Cpp2) | |---|---| | `ushort` | `#!cpp unsigned short` | | `uint` | `#!cpp unsigned int` | | `ulong` | `#!cpp unsigned long` | | `longlong` | `#!cpp long long` | | `ulonglong` | `#!cpp unsigned long long` | | `longdouble` | `#!cpp long double` | | For compatibility/interop only,
so deliberately ugly names | Synonym for (these multi-word
names are not allowed in Cpp2) | Notes | |---|---|---| | `_schar` | `#!cpp signed char` | Normally, prefer `i8` instead | | `_uchar` | `#!cpp unsigned char` | Normally, prefer `u8` instead | ## Type qualifiers Types can be qualified with `#!cpp const` and `#!cpp *`. Types are written left-to-right, so a qualifier always applies to what immediately follows it. For example, to declare a `#!cpp const` pointer to a non-`#!cpp const` pointer to a `#!cpp const i32` object, write: ``` cpp title="Using type qualifiers" // A const pointer to a non-const pointer to a const i32 object p: const * * const i32; ``` ## Literals Cpp2 supports the same `#!cpp 'c'`haracter, `#!cpp "string"`, binary, integer, and floating point literals as Cpp1, including most Unicode encoding prefixes and raw string literals. Cpp2 supports using Cpp1 user-defined literals for compatibility, to support seamlessly using existing libraries. However, because Cpp2 has [unified function call syntax (UFCS)](expressions.md#ufcs), the preferred way to author the equivalent in Cpp2 is to just write a function or type name as a `.` call suffix. For example: - You can create a `u8` value by writing either `u8(123)` or **`123.u8()`**. [^u8using] - You can write a 'constexpr' function like `#!cpp nm: (value: i64) -> my_nanometer_type == { /*...*/ }` that takes an integer and returns a value of a strongly typed "nanometer" type, and then create a `nm` value by writing either `nm(123)` or **`123.nm()`**. Both **`123.nm()`** and **`123.u8()`** are very similar to user-defined literal syntax, and more general. ## Operators Operators have the same precedence and associativity as in Cpp1, but some unary operators that are prefix (always or sometimes) in Cpp1 are postfix (always) in Cpp2. ### Unary operators The operators `!`, `+`, and `-` are prefix, as in Cpp1. For example: ``` cpp title="Using prefix operators" if !vec.empty() { vec.emplace_back( -123.45 ); } ``` | Unary operator | Cpp2 example | Cpp1 equivalent | |---|---|---| | `!` | `!vec.empty()` | `!vec.empty()` | | `+` | `#!cpp +100` | `#!cpp +100` | | `-` | `#!cpp -100` | `#!cpp -100` | The operators `.`, `..`, `*`, `&`, `~`, `++`, `--`, `()`, `[]`, `..<`, `..=`, and `$` are postfix. For example: ``` cpp title="Using postfix operators" // Cpp1 examples, from cppfront's own source code: // address = &(*tokens)[pos + num]; // is_void = *(*u)->identifier == "void"; // Cpp2 equivalents: address = tokens*[pos + num]&; is_void = u**.identifier* == "void"; ``` Postfix notation lets the code read fluidly left-to-right, in the same order in which the operators will be applied, and lets declaration syntax be consistent with usage syntax. For more details, see [Design note: Postfix operators](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators). > Note: The function call syntax `f(x)` calls a namespace-scope function only. The function call syntax `x.f()` is a unified function call syntax (aka UFCS) that calls a type-scope function in the type of `x` if available, otherwise calls the same as `f(x)`. The function call syntax `x..f()` calls a type-scope function only. For details, see [Design note: UFCS](https://github.com/hsutter/cppfront/wiki/Design-note%3A-UFCS). | Unary operator | Cpp2 example | Cpp1 equivalent | |---|---|---| | `#!cpp .` | `#!cpp obj.f()` | `#!cpp obj.f()` | | `#!cpp *` | `#!cpp pobj*.f()` | `#!cpp (*pobj).f()` or `#!cpp pobj->f()` | | `#!cpp &` | `#!cpp obj&` | `#!cpp &obj` | | `#!cpp ~` | `#!cpp val~` | `#!cpp ~val` | | `#!cpp ++` | `#!cpp iter++` | `#!cpp ++iter` | | `#!cpp --` | `#!cpp iter--` | `#!cpp --iter` | | `(` `)` | `#!cpp f( 1, 2, 3)` | `#!cpp f( 1, 2, 3)` | | `[` `]` | `#!cpp vec[123]` | `#!cpp vec[123]` | | `..<` | `#!cpp v.begin().. Note: The `...` pack expansion syntax is also supported. > Note: The `(` `)`, `[` `]`, `..<`, and `..=` operators are treated as postfix unary operators, though they can take additional arguments. > Note: Because `++` and `--` always have in-place update semantics, we never need to remember "use prefix `++`/`--` unless you need a copy of the old value." If you do need a copy of the old value, just take the copy before calling `++`/`--`. When you write a copyable type that overloads `operator++` or `operator--`, cppfront generates also the copy-old-value overload of that function to support natural use of the type from Cpp1 code. ### Binary operators Binary operators are the same as in Cpp1. From highest to lowest precedence: | Binary operators grouped by precedence | |---| | `*`, `/`, `%` | | `+`, `-` | | `<<`, `>>` | | `<=>` | | `<`, `>`, `<=`, `>=` | | `==`, `!=` | | `&` | | `^` | | `|` | | `&&` | | `||` | | `=` and compound assignment | [^u8using]: Or `123.cpp2::u8()` if you aren't `using` the namespace or that specific name.