Skip to content

Commit 36475b6

Browse files
committed
Add definite initialization section
And: - add placeholder for contracts - add some is/as side-by-side examples - add parameter passing styles
1 parent d8d8a5a commit 36475b6

File tree

5 files changed

+129
-10
lines changed

5 files changed

+129
-10
lines changed

docs/cpp2/contracts.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
# Contracts
3+
4+
## Overview
5+
6+
TODO
7+
8+
9+
## Contract groups
10+
11+
TODO
12+
13+
14+
## Customizing the violation handler
15+
16+
TODO

docs/cpp2/expressions.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ There are two kinds of `is`:
7272
- [`pure2-type-safety-1.cpp2`](https://github.com/hsutter/cppfront/tree/main/regression-tests/pure2-type-safety-1.cpp2)
7373
- [`pure2-type-safety-2-with-inspect-expression.cpp2`](https://github.com/hsutter/cppfront/tree/main/regression-tests/pure2-type-safety-2-with-inspect-expression.cpp2)
7474

75+
Here are some `is` queries with their Cpp1 equivalents. In this table, uppercase names are type names, lowercase names are objects, `v` is a `std::variant` where one alternative is `T`, `o` is a `std::optional<T>`, and `a` is a `std::any`:
76+
77+
| Some sample `is` queries | Cpp1 equivalent
78+
|---|---|
79+
| `X is Y && Y is X` | `std::is_same_v<X,Y>` |
80+
| `D is B` | `std::is_base_of<B,D>` |
81+
| `pb is *D` | `dynamic_cast<D*>(pb) != nullptr` |
82+
| `v is T` | `std::holds_alternative<T>(v)` |
83+
| `a is T` | `a.type() == typeid(T)` |
84+
| `o is T` | `o.has_value()` |
85+
7586

7687
## `as` — safe casts and conversions
7788

@@ -97,6 +108,17 @@ test: (x) = {
97108
}
98109
```
99110

111+
Here are some `as` casts with their Cpp1 equivalents. In this table, uppercase names are type names, lowercase names are objects, `v` is a `std::variant` where one alternative is `T`, `o` is a `std::optional<T>`, and `a` is a `std::any`:
112+
113+
| Some sample `as` casts | Cpp1 equivalent
114+
|---|---|
115+
| `x as Y` | `Y{x}` |
116+
| `pb as *D` | `dynamic_cast<D*>(pb)` |
117+
| `v as T` | `std::get<T>(v)` |
118+
| `a as T` | `std::any_cast<T>(a)` |
119+
| `o as T` | `o.value()` |
120+
121+
100122
## `inspect` — pattern matching
101123

102124
An `inspect expr -> Type` expression allows pattern matching using `is`.

docs/cpp2/functions.md

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
TODO
77

8-
## Calling functions: Nonmember function syntax, and UFCS syntax
8+
## Calling functions: `f(x)` syntax, and `x.f()` UFCS syntax
99

1010
A function call like `f(x)` is a normal non-member function call. It will call non-member functions only.
1111

@@ -15,22 +15,38 @@ For example:
1515

1616
``` cpp title="Example: Function calls"
1717
f: ( v : std::vector<widget> ) = {
18-
1918
// This calls std::vector::size()
2019
std::cout << v.size();
2120

2221
// This calls std::ssize(v), because v
2322
// doesn't have a .ssize member function
2423
std::cout << v.ssize();
2524
}
26-
```
2725

28-
If the function has an output that cannot be silently discarded, you can
26+
// Generic function to print "hello, ___!" for any printable type
27+
hello: (name) = {
28+
// Using the C standard library is arguably nicer with UFCS
29+
myfile := fopen("xyzzy.txt", "w");
30+
myfile.fprintf( "Hello, (name)%!\n" );
31+
myfile.fclose();
32+
}
33+
```
2934

3035

3136
## Parameters
3237

33-
TODO
38+
There are six ways to pass parameters that cover all use cases:
39+
40+
| Parameter kind | "Pass me an `x` I can ______" | Accepts arguments that are | Special semantics |
41+
|---|---|---|---|
42+
| `in` (default) | read from | anything | always `const`<p>automatically passes by value if cheaply copyable |
43+
| `copy` | take a copy of | anything | acts like a normal local variable initialized with the argument |
44+
| `inout` | read from and write to | lvalues | |
45+
| `out` | write to (including construct) | lvalues, including uninitialized lvalues | must `=` assign/construct before other uses |
46+
| `move` | move from | rvalues | automatically moves from every definite last use |
47+
| `forward` | forward | anything | automatically forwards from every definite last use |
48+
49+
3450

3551
> Note: All parameters and other objects in Cpp2 are `const` by default, except for local variables. For details, see [Design note: `const` objects by default](https://github.com/hsutter/cppfront/wiki/Design-note%3A-const-objects-by-default).
3652

docs/cpp2/objects.md

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,75 @@ count := -1; // same, deducing the object's type by just omitting it
2626
```
2727

2828

29+
## Guaranteed initialization
30+
31+
Every object must be initialized using `=` before it is used.
32+
33+
An object in any scope can be initialized at its declaration. For example:
34+
35+
``` cpp title="Example: Initializing objects when they are declared" hl_lines="4 10"
36+
shape: type = {
37+
// An object at type scope (data member)
38+
// initialized with its type's default value
39+
points: std::vector<point2d> = ();
40+
41+
draw: (this, where: canvas) -> bool
42+
= {
43+
// An object at function scope (local variable)
44+
// initialized with color::red
45+
pen := color::red;
46+
47+
// ...
48+
}
49+
50+
// ...
51+
}
52+
```
53+
54+
Additionally, at function local scope an object `obj` can be initialized separately from its declaration. This can be useful when the object must be declared before a program-meaningful initial value is known (to avoid a dead write of a wrong 'dummy' value), and/or when the object may be initialized in more than one way depending on other logic (e.g., by using different constructors on different paths). The way to do this is:
55+
56+
- Declare `obj` without an initializer, such as `obj: some_type;`. This allocates stack space for the object, but does not construct it.
57+
58+
- `obj` must have a definite first use on every `if`/`else` branch path, and
59+
60+
- that definite first use must be of the form `obj = value;` which is a constructor call, or else pass `obj` as an `out` argument to an `out` parameter (which is also effectively a constructor call, and performs the construction in the callee).
61+
62+
For example:
63+
64+
``` cpp title="Example: Initializing local objects after they are declared"
65+
f: () = {
66+
buf: std::array<std::byte, 1024>; // uninitialized
67+
// ... calculate some things ...
68+
// ... no uses of buf here ...
69+
buf = some_calculated_value; // constructs (not assigns) buf
70+
// ...
71+
std::cout buf[0]; // ok, a has been initialized
72+
}
73+
74+
g: () = {
75+
buf: std::array<std::byte, 1024>; // uninitialized
76+
if flip_coin_is_heads() {
77+
if heads_default_is_available {
78+
buf = copy_heads_default(); // constructs buf
79+
}
80+
else {
81+
buf = (other, constructor); // constructs buf
82+
}
83+
}
84+
else {
85+
load_from_disk( out buf ); // constructs buf (*)
86+
}
87+
std::cout buf[0]; // ok, a has been initialized
88+
}
89+
90+
load_from_disk: (out buffer) = {
91+
x = /* data read from disk */ ; // when `buffer` is uninitialized,
92+
} // constructs it; otherwise, assigns
93+
```
94+
95+
In the above example, note the simple rule for branches: The local variable must be initialized on both the `if` and `else` branches, or neither branch.
96+
97+
2998
## Heap objects
3099

31100
Objects can also be allocated on the heap using `arena.new <T> (/*initializer, arguments)` where `arena` is any object that acts as a memory arena and provides a `.new` function template. Two memory arena objects are provided in namespace `cpp2`:
@@ -58,8 +127,3 @@ f: () -> std::shared_ptr<widget>
58127
// destroys the heap vector and deallocates its dynamic memory
59128
```
60129

61-
62-
## Guaranteed initialization
63-
64-
TODO
65-

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ nav:
5959
- 'Declaration syntax': cpp2/declarations.md
6060
- 'Objects, initialization, and memory': cpp2/objects.md
6161
- 'Functions': cpp2/functions.md
62+
- 'Contracts': cpp2/contracts.md
6263
- 'Types': cpp2/types.md
6364
- 'Metafunctions & reflection API': cpp2/metafunctions.md
6465
- 'Namespaces': cpp2/namespaces.md

0 commit comments

Comments
 (0)