|
| 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="lists"></a> Lists and commas |
| 59 | + |
| 60 | +All lists use `,` commas between list items, and may be enclosed by |
| 61 | + |
| 62 | +- `(` `)` parentheses, for most lists |
| 63 | + |
| 64 | +- `[` `]` brackets, for calling the subscript operator |
| 65 | + |
| 66 | +- `<` `>` angle brackets, for template parameter/argument lists |
| 67 | + |
| 68 | +For example: |
| 69 | + |
| 70 | +``` cpp title="Lists, using optional trailing commas just because we can" hl_lines="1 4 6 7" |
| 71 | +print: <T,U> (t: T, u: U) = std::cout << t << u << "\n"; |
| 72 | + |
| 73 | +main: () = { |
| 74 | + array: std::array = ('A', 'B', 'C'); |
| 75 | + |
| 76 | + for (0, 1, 2) do (e) { |
| 77 | + print( e, array[e] ); |
| 78 | + } |
| 79 | + // Prints: |
| 80 | + // 0A |
| 81 | + // 1B |
| 82 | + // 2C |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | + |
| 87 | +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)). |
| 88 | + |
| 89 | +For example: |
| 90 | + |
| 91 | +``` cpp title="Lists, using optional trailing commas just because we can" hl_lines="1 4 6 7" |
| 92 | +print: <T,U,> (t: T, u: U,) = std::cout << t << u << "\n"; |
| 93 | + |
| 94 | +main: () = { |
| 95 | + array: std::array = ('A', 'B', 'C',); |
| 96 | + |
| 97 | + for (0, 1, 2,) do (e) { |
| 98 | + print( e, array[e,], ); |
| 99 | + } |
| 100 | + // Prints: |
| 101 | + // 0A |
| 102 | + // 1B |
| 103 | + // 2C |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | + |
| 108 | +## <a id="keywords"></a> Reserved keywords |
| 109 | + |
| 110 | +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: |
| 111 | + |
| 112 | +- `new` is used as an ordinary function to do allocation (e.g., `shared.new<widget>(1, 2, 3)`). |
| 113 | + |
| 114 | +- `struct` and `enum` are used as function names in the metafunctions library. |
| 115 | + |
| 116 | +- `type` can be used as an ordinary name (e.g., `std::common_type<T1,T2>::type`). |
| 117 | + |
| 118 | +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). |
| 119 | + |
| 120 | + |
| 121 | +## <a id="fundamental-types"></a> Fundamental data types |
| 122 | + |
| 123 | +Cpp2 supports the same fundamental types as today's Cpp1, but additionally provides the following aliases in namespace `cpp2`: |
| 124 | + |
| 125 | +| Fixed-width types | Synonym for | |
| 126 | +|---|---| |
| 127 | +| `i8` | `std::int8_t` | |
| 128 | +| `i16` | `std::int16_t` | |
| 129 | +| `i32` | `std::int32_t` | |
| 130 | +| `i64` | `std::int64_t` | |
| 131 | +| `u8` | `std::uint8_t` | |
| 132 | +| `u16` | `std::uint16_t` | |
| 133 | +| `u32` | `std::uint32_t` | |
| 134 | +| `u64` | `std::uint64_t` | |
| 135 | + |
| 136 | +| Variable-width types <br> (Cpp2-compatible single-word names) | Synonym for (these multi-word<br> names are not allowed in Cpp2) | |
| 137 | +|---|---| |
| 138 | +| `ushort` | `#!cpp unsigned short` | |
| 139 | +| `uint` | `#!cpp unsigned int` | |
| 140 | +| `ulong` | `#!cpp unsigned long` | |
| 141 | +| `longlong` | `#!cpp long long` | |
| 142 | +| `ulonglong` | `#!cpp unsigned long long` | |
| 143 | +| `longdouble` | `#!cpp long double` | |
| 144 | + |
| 145 | +| For compatibility/interop only,<br> so deliberately ugly names | Synonym for (these multi-word<br> names are not allowed in Cpp2) | Notes | |
| 146 | +|---|---|---| |
| 147 | +| `_schar` | `#!cpp signed char` | Normally, prefer `i8` instead | |
| 148 | +| `_uchar` | `#!cpp unsigned char` | Normally, prefer `u8` instead | |
| 149 | + |
| 150 | +## <a id="type-qualifiers"></a> Type qualifiers |
| 151 | + |
| 152 | +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: |
| 153 | + |
| 154 | +``` cpp title="Using type qualifiers" |
| 155 | +// A const pointer to a non-const pointer to a const i32 object |
| 156 | +p: const * * const i32; |
| 157 | +``` |
| 158 | + |
| 159 | +## <a id="literals"></a> Literals |
| 160 | + |
| 161 | +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. |
| 162 | + |
| 163 | +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: |
| 164 | + |
| 165 | +- You can create a `u8` value by writing either `u8(123)` or **`123.u8()`**. [^u8using] |
| 166 | + |
| 167 | +- 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()`**. |
| 168 | + |
| 169 | +Both **`123.nm()`** and **`123.u8()`** are very similar to user-defined literal syntax, and more general. |
| 170 | + |
| 171 | +## <a id="operators"></a> Operators |
| 172 | + |
| 173 | +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. |
| 174 | + |
| 175 | +### <a id="unary-operators"></a> Unary operators |
| 176 | + |
| 177 | +The operators `!`, `+`, and `-` are prefix, as in Cpp1. For example: |
| 178 | + |
| 179 | +``` cpp title="Using prefix operators" |
| 180 | +if !vec.empty() { |
| 181 | + vec.emplace_back( -123.45 ); |
| 182 | +} |
| 183 | +``` |
| 184 | + |
| 185 | +| Unary operator | Cpp2 example | Cpp1 equivalent | |
| 186 | +|---|---|---| |
| 187 | +| `!` | `!vec.empty()` | `!vec.empty()` | |
| 188 | +| `+` | `#!cpp +100` | `#!cpp +100` | |
| 189 | +| `-` | `#!cpp -100` | `#!cpp -100` | |
| 190 | + |
| 191 | +The operators `.`, `*`, `&`, `~`, `++`, `--`, `()`, `[]`, and `$` are postfix. For example: |
| 192 | + |
| 193 | +``` cpp title="Using postfix operators" |
| 194 | +// Cpp1 examples, from cppfront's own source code: |
| 195 | +// address = &(*tokens)[pos + num]; |
| 196 | +// is_void = *(*u)->identifier == "void"; |
| 197 | +// Cpp2 equivalents: |
| 198 | + address = tokens*[pos + num]&; |
| 199 | + is_void = u**.identifier* == "void"; |
| 200 | +``` |
| 201 | + |
| 202 | +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). |
| 203 | + |
| 204 | +> 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). |
| 205 | +
|
| 206 | +| Unary operator | Cpp2 example | Cpp1 equivalent | |
| 207 | +|---|---|---| |
| 208 | +| `#!cpp .` | `#!cpp obj.f()` | `#!cpp obj.f()` | |
| 209 | +| `#!cpp *` | `#!cpp pobj*.f()` | `#!cpp (*pobj).f()` or `#!cpp pobj->f()` | |
| 210 | +| `#!cpp &` | `#!cpp obj&` | `#!cpp &obj` | |
| 211 | +| `#!cpp ~` | `#!cpp val~` | `#!cpp ~val` | |
| 212 | +| `#!cpp ++` | `#!cpp iter++` | `#!cpp ++iter` | |
| 213 | +| `#!cpp --` | `#!cpp iter--` | `#!cpp --iter` | |
| 214 | +| `(` `)` | `#!cpp f( 1, 2, 3)` | `#!cpp f( 1, 2, 3)` | |
| 215 | +| `[` `]` | `#!cpp vec[123]` | `#!cpp vec[123]` | |
| 216 | +| `$` | `val$` | _reflection — no Cpp1 equivalent yet_ | |
| 217 | + |
| 218 | +> 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 `++`/`--`. |
| 219 | +
|
| 220 | +Unary suffix operators must not be preceded by whitespace. When `*`, `&`, and `~` are used as binary operators they must be preceded by whitespace. For example: |
| 221 | + |
| 222 | +| Unary postfix operators that<br>are also binary operators | Cpp2 example | Cpp1 equivalent | |
| 223 | +|---|---|---| |
| 224 | +| `#!cpp *` | `#!cpp pobj* * 42` | `#!cpp (*pobj)*42` | |
| 225 | +| `#!cpp &` | `#!cpp obj& & mask` <p> (note: allowed in unsafe code only) | `#!cpp &obj & mask` | |
| 226 | + |
| 227 | +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). |
| 228 | + |
| 229 | + |
| 230 | +### <a id="binary-operators"></a> Binary operators |
| 231 | + |
| 232 | +Binary operators are the same as in Cpp1. From highest to lowest precedence: |
| 233 | + |
| 234 | +| Binary operators grouped by precedence | |
| 235 | +|---| |
| 236 | +| `*`, `/`, `%` | |
| 237 | +| `+`, `-` | |
| 238 | +| `<<`, `>>` | |
| 239 | +| `<=>` | |
| 240 | +| `<`, `>`, `<=`, `>=` | |
| 241 | +| `==`, `!=` | |
| 242 | +| `&` | |
| 243 | +| `^` | |
| 244 | +| `|` | |
| 245 | +| `&&` | |
| 246 | +| `||` | |
| 247 | +| `=` and compound assignment | |
| 248 | + |
| 249 | + |
| 250 | +[^u8using]: Or `123.cpp2::u8()` if you aren't `using` the namespace or that specific name. |
0 commit comments