|
| 1 | +# Common programming concepts |
| 2 | + |
| 3 | +## <a id="main"></a> `main` |
| 4 | + |
| 5 | +As always, `main` is the entry point of the program. For example: |
| 6 | + |
| 7 | +`main` can have either: |
| 8 | + |
| 9 | +- No parameters:   **`#!cpp main: () /*etc.*/`** |
| 10 | + |
| 11 | +- One parameter of implicit type named `args`:   **`#!cpp main: (args) /*etc.*/`** |
| 12 | + |
| 13 | + - The type of `args` cannot be explicitly specified. It is always `cpp2::args_t`, which behaves similarly to a `#!cpp const std::array<std::string_view>`. |
| 14 | + |
| 15 | + - Using `args` performs zero heap allocations. Every `string_view` is directly bound to the string storage provided by host environment. |
| 16 | + |
| 17 | + - `args.argc` and `args.argv` additionally provide access to the raw C/C++ `main` parameters. |
| 18 | + |
| 19 | +``` cpp title="main with (args)" hl_lines="5 9" |
| 20 | +// Print out command line arguments, then invoke |
| 21 | +// a Qt event loop for a non-UI Qt application |
| 22 | +main: (args) -> int |
| 23 | += { |
| 24 | + for args do (arg) { |
| 25 | + std::cout << arg << "\n"; |
| 26 | + } |
| 27 | + |
| 28 | + app: QCoreApplication = (args.argc, args.argv); |
| 29 | + return app.exec(); |
| 30 | +} |
| 31 | +``` |
| 32 | + |
| 33 | +`main` can return: |
| 34 | + |
| 35 | +- `#!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`. |
| 36 | + |
| 37 | +- `#!cpp int`. If the body has no `#!cpp return` statement, the default is to `#!cpp return 0;` at the end of the function body. |
| 38 | + |
| 39 | +- Some other type that your Cpp1 compiler(s) supports as a nonstandard extension. |
| 40 | + |
| 41 | + |
| 42 | +## <a id="comments"></a> Comments |
| 43 | + |
| 44 | +The usual `#!cpp // line comments` and `#!cpp /* stream comments */` are supported. For example: |
| 45 | + |
| 46 | +``` cpp title="Writing comments" |
| 47 | +// A line comment: After //, the entire |
| 48 | +// rest of the line is part of the comment |
| 49 | + |
| 50 | +/* |
| 51 | + A stream comment: After /*, everything until the |
| 52 | + next * / (without a space between) is part of the |
| 53 | + comment. Note that stream comments do not nest. |
| 54 | + */ |
| 55 | +``` |
| 56 | + |
| 57 | + |
| 58 | +## <a id="keywords"></a> Reserved keywords |
| 59 | + |
| 60 | +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: |
| 61 | + |
| 62 | +- `new` is used as an ordinary function to do allocation (e.g., `shared.new<widget>(1, 2, 3)`). |
| 63 | + |
| 64 | +- `struct` and `enum` are used as function names in the metafunctions library. |
| 65 | + |
| 66 | +- `type` can be used as an ordinary name (e.g., `std::common_type<T1,T2>::type`). |
| 67 | + |
| 68 | +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). |
| 69 | + |
| 70 | + |
| 71 | +## <a id="fundamental-types"></a> Fundamental data types |
| 72 | + |
| 73 | +Cpp2 supports the same fundamental types as today's Cpp1, but additionally provides the following aliases in namespace `cpp2`: |
| 74 | + |
| 75 | +| Fixed-width types | Synonym for | |
| 76 | +|---|---| |
| 77 | +| `i8` | `std::int8_t` | |
| 78 | +| `i16` | `std::int16_t` | |
| 79 | +| `i32` | `std::int32_t` | |
| 80 | +| `i64` | `std::int64_t` | |
| 81 | +| `u8` | `std::uint8_t` | |
| 82 | +| `u16` | `std::uint16_t` | |
| 83 | +| `u32` | `std::uint32_t` | |
| 84 | +| `u64` | `std::uint64_t` | |
| 85 | + |
| 86 | +| Variable-width types <br> (Cpp2-compatible single-word names) | Synonym for (these multi-word<br> names are not allowed in Cpp2) | |
| 87 | +|---|---| |
| 88 | +| `ushort` | `#!cpp unsigned short` | |
| 89 | +| `uint` | `#!cpp unsigned int` | |
| 90 | +| `ulong` | `#!cpp unsigned long` | |
| 91 | +| `longlong` | `#!cpp long long` | |
| 92 | +| `ulonglong` | `#!cpp unsigned long long` | |
| 93 | +| `longdouble` | `#!cpp long double` | |
| 94 | + |
| 95 | +| For compatibility/interop only,<br> so deliberately ugly names | Synonym for (these multi-word<br> names are not allowed in Cpp2) | Notes | |
| 96 | +|---|---|---| |
| 97 | +| `_schar` | `#!cpp signed char` | Normally, prefer `i8` instead | |
| 98 | +| `_uchar` | `#!cpp unsigned char` | Normally, prefer `u8` instead | |
| 99 | + |
| 100 | +## <a id="type-qualifiers"></a> Type qualifiers |
| 101 | + |
| 102 | +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: |
| 103 | + |
| 104 | +``` cpp title="Using type qualifiers" |
| 105 | +// A const pointer to a non-const pointer to a const i32 object |
| 106 | +p: const * * const i32; |
| 107 | +``` |
| 108 | + |
| 109 | +## <a id="literals"></a> Literals |
| 110 | + |
| 111 | +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. |
| 112 | + |
| 113 | +Cpp2 supports using Cpp1 user-defined literals for compatibility, to support seamlessly using existing libraries. However, because Cpp2 has unified function call syntax (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: |
| 114 | + |
| 115 | +- You can create a `u8` value by writing either `u8(123)` or **`123.u8()`**. [^u8using] |
| 116 | + |
| 117 | +- 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()`**. |
| 118 | + |
| 119 | +Both **`123.nm()`** and **`123.u8()`** are very similar to user-defined literal syntax, and more general. |
| 120 | + |
| 121 | +## <a id="operators"></a> Operators |
| 122 | + |
| 123 | +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. |
| 124 | + |
| 125 | +### <a id="unary-operators"></a> Unary operators |
| 126 | + |
| 127 | +The operators `!`, `+`, and `-` are prefix, as in Cpp1. For example: |
| 128 | + |
| 129 | +``` cpp title="Using prefix operators" |
| 130 | +if !vec.empty() { |
| 131 | + vec.emplace_back( -123.45 ); |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +| Unary operator | Cpp2 example | Cpp1 equivalent | |
| 136 | +|---|---|---| |
| 137 | +| `!` | `!vec.empty()` | `!vec.empty()` | |
| 138 | +| `+` | `#!cpp +100` | `#!cpp +100` | |
| 139 | +| `-` | `#!cpp -100` | `#!cpp -100` | |
| 140 | + |
| 141 | +The operators `.`, `*`, `&`, `~`, `++`, `--`, `()`, `[]`, and `$` are postfix. For example: |
| 142 | + |
| 143 | +``` cpp title="Using postfix operators" |
| 144 | +// Cpp1 examples, from cppfront's own source code: |
| 145 | +// address = &(*tokens)[pos + num]; |
| 146 | +// is_void = *(*u)->identifier == "void"; |
| 147 | +// Cpp2 equivalents: |
| 148 | + address = tokens*[pos + num]&; |
| 149 | + is_void = u**.identifier* == "void"; |
| 150 | +``` |
| 151 | + |
| 152 | +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). |
| 153 | + |
| 154 | +> Note: The function call syntax `f(x)` calls a namespace-scope function, or a function object, named `f`. 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)`. For details, see [Design note: UFCS](https://github.com/hsutter/cppfront/wiki/Design-note%3A-UFCS). |
| 155 | +
|
| 156 | +| Unary operator | Cpp2 example | Cpp1 equivalent | |
| 157 | +|---|---|---| |
| 158 | +| `#!cpp .` | `#!cpp obj.f()` | `#!cpp obj.f()` | |
| 159 | +| `#!cpp *` | `#!cpp pobj*.f()` | `#!cpp (*pobj).f()` or `#!cpp pobj->f()` | |
| 160 | +| `#!cpp &` | `#!cpp obj&` | `#!cpp &obj` | |
| 161 | +| `#!cpp ~` | `#!cpp val~` | `#!cpp ~val` | |
| 162 | +| `#!cpp ++` | `#!cpp iter++` | `#!cpp ++iter` | |
| 163 | +| `#!cpp --` | `#!cpp iter--` | `#!cpp --iter` | |
| 164 | +| `(` `)` | `#!cpp f( 1, 2, 3)` | `#!cpp f( 1, 2, 3)` | |
| 165 | +| `[` `]` | `#!cpp vec[123]` | `#!cpp vec[123]` | |
| 166 | +| `$` | `val$` | _reflection — no Cpp1 equivalent yet_ | |
| 167 | + |
| 168 | +> 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 `++`/`--`. |
| 169 | +
|
| 170 | +Unary suffix operators must not be preceded by whitespace. When `*`, `&`, and `~` are used as binary operators they must be preceded by whitespace. For example: |
| 171 | + |
| 172 | +| Unary postfix operators that<br>are also binary operators | Cpp2 example | Cpp1 equivalent | |
| 173 | +|---|---|---| |
| 174 | +| `#!cpp *` | `#!cpp pobj* * 42` | `#!cpp (*pobj)*42` | |
| 175 | +| `#!cpp &` | `#!cpp obj& & mask` <p> (note: allowed in unsafe code only) | `#!cpp &obj & mask` | |
| 176 | +| `#!cpp ~` | `#!cpp ~val ~ bitcomplement` | `#!cpp val~ ~ bitcomplement` | |
| 177 | + |
| 178 | +For more details, see [Design note: Postfix unary operators vs binary operators](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-unary-operators-vs-binary-operators). |
| 179 | + |
| 180 | + |
| 181 | +### <a id="binary-operators"></a> Binary operators |
| 182 | + |
| 183 | +Binary operators are the same as in Cpp1. From highest to lowest precedence: |
| 184 | + |
| 185 | +| Binary operators grouped by precedence | |
| 186 | +|---| |
| 187 | +| `*`, `/`, `%` | |
| 188 | +| `+`, `-` | |
| 189 | +| `<<`, `>>` | |
| 190 | +| `<=>` | |
| 191 | +| `<`, `>`, `<=`, `>=` | |
| 192 | +| `==`, `!=` | |
| 193 | +| `&` | |
| 194 | +| `^` | |
| 195 | +| `|` | |
| 196 | +| `&&` | |
| 197 | +| `||` | |
| 198 | +| `=` and compound assignment | |
| 199 | + |
| 200 | + |
| 201 | +[^u8using]: Or `123.cpp2::u8()` if you aren't `using` the namespace or that specific name. |
0 commit comments