Skip to content

Commit

Permalink
docs fix
Browse files Browse the repository at this point in the history
  • Loading branch information
thradams committed Nov 20, 2024
1 parent d0db6fa commit d2a3f01
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 40 deletions.
77 changes: 57 additions & 20 deletions ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,40 @@ This warning relies on flow analysis, which ensures that the potential nullabili
#### Non nullable members

The concept of nullable types is present in some language like C# and Typescript.
Both languages have the concept of `constructor` for objects. So, for objects members, the compiler checks if after the constructor the non-nullable members have being assigned to a non null value.
Both languages have the concept of object constructor. For object members, the compiler checks if
after the constructor the non-nullable members have being assigned to a non null value.

The other way to see this, is that during construction the non nullable pointer member can be null, before they receive a value.
For instance, in Typescript

In C, we don t have the concept of constructor, so the same approach cannot be applied directly.
```ts
class Y {
public i = 0;
}

class X
{
public readonly i : number;
public pY : Y;
constructor(){
//Property 'pY' has no initializer and is not definitely assigned
//in the constructor.(2564)
//this.pY = new Y;
//this.i = 1;
}
}

```

https://www.typescriptlang.org/play/?#code/MYGwhgzhAECa0G9oChrQA4FcBGICWw0e0AvNAAwDcKAvssqJDABopKoY76EBOApmAAmAewB2IAJ5FoALmijMAW2x8e1DllwEM8ObGoo0wMRAAuPTMFPCeACgCUCDmgD0LgAo9h6VaakBydFh-aAALSHlhIlE8UzwwfAAvVWgwUUEiGFFhU2hBPgAzPBjTPklUqDwAc1E+DOdoN2LoU1C+aGNRMwsrGwA6WwAmAFYANgAWezQ0BrdWvAg+oNJ5PgB3OEpZl3nF4jIARi20OjogA


The other way to see this, is that during construction the invariant of the object is not complete yet.

In C, we don t have the concept of constructor, so the same approach cannot be applied directly.

Cake, have a mechanism using the qualifier `_Opt` before struct types to make all non-nullable members as nullable for a particular instance.
This allow us the have a object where the invariant is not completed.


```c
struct X {
Expand All @@ -124,11 +151,16 @@ struct X * _Opt makeX(const char* name)
}
```
<button onclick="Try(this)">try</button>
<button onclick="Try(this)">try</button>
The particular instance of p, that has being qualified with \_Opt, is allowed to have no-nullable members with a null values.
Just like in C# or Typescript, we cannot leave this function with a nullable member being null. But the particular instance of p is allowed to have nullable members.
However, we cannot leave this function with a non-nullable member being null because the result of
the function is not \_Opt qualified.
This approach makes it possible to have an alternative design for constructors.
This is also useful to accept for some functions like destructor, partially constructed object.
This state is also useful for some functions like destructor, to be able to destroy partially constructed objects.
For instance:
```c
void x_destroy(_Opt struct X * p)
Expand All @@ -137,9 +169,16 @@ void x_destroy(_Opt struct X * p)
}
```

>Note : This design may change and be replaced by mutable.
#### mutable

Note that this concept also could be applied for const members.

The introduction of a **mutable** qualifier allows certain exceptions to the usual contract of immutability and non-nullability during transitional phases, such as in constructors and destructors. This means that objects marked as **mutable** can temporarily violate their normal constraints, such as modifying `const` members or assigning null to non-nullable pointers during these phases.
The introduction of a **mutable** qualifier allows certain exceptions to the usual contract
of immutability and non-nullability during transitional phases, such as in constructors and destructors.
This means that objects marked as **mutable** can temporarily violate their normal constraints,
such as modifying `const` members or assigning null to non-nullable pointers during these phases.

Consider the following code example:

Expand All @@ -163,9 +202,17 @@ struct X * _Opt makeX(const char* name)
}
```
In this example, `struct X` has a `const` member `name`, which is non-nullable. Under normal conditions, modifying a `const` member after initialization would be disallowed. However, the **mutable** qualifier temporarily relaxes this rule during the object’s creation process, allowing modifications even to `const` members, and allowing a non-nullable pointer to be null before the object’s initialization completes.
In this example, `struct X` has a `const` member `name`, which is non-nullable.
Under normal conditions, modifying a `const` member after initialization would be disallowed.
However, the **mutable** qualifier temporarily relaxes this rule during the object’s creation process,
allowing modifications even to `const` members, and allowing a non-nullable pointer to be null
before the object’s initialization completes.
We also have an implicit contract for struct members. Generally, we assume that members are initialized, but we lack a qualifier to explicitly indicate "initialized member." For instance, when using malloc, members are initially uninitialized, but they should receive a value before being used.
We also have an implicit contract for struct members.
Generally, we assume that members are initialized, but we lack a qualifier to explicitly
indicate "initialized member."
For instance, when using malloc, members are initially uninitialized, but they should receive a value before being used.
```c
struct X * _Opt makeX(const char* name)
Expand All @@ -184,17 +231,7 @@ struct X * _Opt makeX(const char* name)
}
```


##### Transitional State:
During the object creation (or destruction), the instance is considered to be in a transitional state, where the usual constraints—such as non-nullable pointers and immutability—are lifted. For example, in the `makeX` function, `p->name` can be set to `temp`, even though `name` is `const`. This allows flexibility during initialization, after which the object is returned to its normal state with the contract fully enforced.

##### Effect on the Final Object:
Once the transitional phase is over and the object is returned, the contract that governs the object (such as immutability of `name` and non-nullability of pointers) is fully reinstated. The **mutable** qualifier only applies within the scope of the constructor or destructor, ensuring that once the object is fully constructed, its state is valid and consistent with the type system’s rules.

This approach allows for more flexibility during object creation while maintaining strong contracts once the object is finalized, enhancing both safety and expressiveness in the code.


OBS: mutable qualifier is not yet implemented in Cake. However, _Opt for structs is implemented.
>OBS: mutable qualifier is not yet implemented in Cake. However, _Opt for structs is implemented and may be replaced in the future

### Object lifetime checks
Expand Down
78 changes: 58 additions & 20 deletions src/web/ownership.html
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,37 @@ <h4>Example 3: Diagnostic for Nullable to Non-Nullable Conversion</h4>
<h4>Non nullable members</h4>

<p>The concept of nullable types is present in some language like C# and Typescript.
Both languages have the concept of <code>constructor</code> for objects. So, for objects members, the compiler checks if after the constructor the non-nullable members have being assigned to a non null value.</p>
Both languages have the concept of object constructor. For object members, the compiler checks if
after the constructor the non-nullable members have being assigned to a non null value.</p>

<p>The other way to see this, is that during construction the non nullable pointer member can be null, before they receive a value.</p>
<p>For instance, in Typescript</p>

<p>In C, we don t have the concept of constructor, so the same approach cannot be applied directly.</p>
<pre><code class="language-ts">class Y {
public i = 0;
}

class X
{
public readonly i : number;
public pY : Y;
constructor(){
//Property &#39;pY&#39; has no initializer and is not definitely assigned
//in the constructor.(2564)
//this.pY = new Y;
//this.i = 1;
}
}

</code></pre>

<p>Cake, have a mechanism using the qualifier <code>_Opt</code> before struct types to make all non-nullable members as nullable for a particular instance.</p>
<p><a href="https://www.typescriptlang.org/play/?#code/MYGwhgzhAECa0G9oChrQA4FcBGICWw0e0AvNAAwDcKAvssqJDABopKoY76EBOApmAAmAewB2IAJ5FoALmijMAW2x8e1DllwEM8ObGoo0wMRAAuPTMFPCeACgCUCDmgD0LgAo9h6VaakBydFh-aAALSHlhIlE8UzwwfAAvVWgwUUEiGFFhU2hBPgAzPBjTPklUqDwAc1E+DOdoN2LoU1C+aGNRMwsrGwA6WwAmAFYANgAWezQ0BrdWvAg+oNJ5PgB3OEpZl3nF4jIARi20OjogA">https://www.typescriptlang.org/play/?#code/MYGwhgzhAECa0G9oChrQA4FcBGICWw0e0AvNAAwDcKAvssqJDABopKoY76EBOApmAAmAewB2IAJ5FoALmijMAW2x8e1DllwEM8ObGoo0wMRAAuPTMFPCeACgCUCDmgD0LgAo9h6VaakBydFh-aAALSHlhIlE8UzwwfAAvVWgwUUEiGFFhU2hBPgAzPBjTPklUqDwAc1E+DOdoN2LoU1C+aGNRMwsrGwA6WwAmAFYANgAWezQ0BrdWvAg+oNJ5PgB3OEpZl3nF4jIARi20OjogA</a></p>

<p>The other way to see this, is that during construction the invariant of the object is not complete yet.</p>

<p>In C, we don t have the concept of constructor, so the same approach cannot be applied directly.</p>

<p>Cake, have a mechanism using the qualifier <code>_Opt</code> before struct types to make all non-nullable members as nullable for a particular instance.
This allow us the have a object where the invariant is not completed.</p>

<pre><code class="language-c">struct X {
char * name; //non nullable
Expand All @@ -176,19 +200,33 @@ <h4>Non nullable members</h4>

<p><button onclick="Try(this)">try</button></p>

<p>Just like in C# or Typescript, we cannot leave this function with a nullable member being null. But the particular instance of p is allowed to have nullable members.</p>
<p>The particular instance of p, that has being qualified with _Opt, is allowed to have no-nullable members with a null values.</p>

<p>This is also useful to accept for some functions like destructor, partially constructed object.</p>
<p>However, we cannot leave this function with a non-nullable member being null because the result of
the function is not _Opt qualified.
This approach makes it possible to have an alternative design for constructors.</p>

<p>This state is also useful for some functions like destructor, to be able to destroy partially constructed objects.
For instance:</p>

<pre><code class="language-c">void x_destroy(_Opt struct X * p)
{
free(p-&gt;name); //ok
}
</code></pre>

<blockquote>
<p>Note : This design may change and be replaced by mutable.</p>
</blockquote>

<h4>mutable</h4>

<p>Note that this concept also could be applied for const members. </p>

<p>The introduction of a <strong>mutable</strong> qualifier allows certain exceptions to the usual contract of immutability and non-nullability during transitional phases, such as in constructors and destructors. This means that objects marked as <strong>mutable</strong> can temporarily violate their normal constraints, such as modifying <code>const</code> members or assigning null to non-nullable pointers during these phases.</p>
<p>The introduction of a <strong>mutable</strong> qualifier allows certain exceptions to the usual contract
of immutability and non-nullability during transitional phases, such as in constructors and destructors.
This means that objects marked as <strong>mutable</strong> can temporarily violate their normal constraints,
such as modifying <code>const</code> members or assigning null to non-nullable pointers during these phases.</p>

<p>Consider the following code example:</p>

Expand All @@ -211,9 +249,17 @@ <h4>Non nullable members</h4>
}
</code></pre>

<p>In this example, <code>struct X</code> has a <code>const</code> member <code>name</code>, which is non-nullable. Under normal conditions, modifying a <code>const</code> member after initialization would be disallowed. However, the <strong>mutable</strong> qualifier temporarily relaxes this rule during the object’s creation process, allowing modifications even to <code>const</code> members, and allowing a non-nullable pointer to be null before the object’s initialization completes.</p>
<p>In this example, <code>struct X</code> has a <code>const</code> member <code>name</code>, which is non-nullable.
Under normal conditions, modifying a <code>const</code> member after initialization would be disallowed. </p>

<p>We also have an implicit contract for struct members. Generally, we assume that members are initialized, but we lack a qualifier to explicitly indicate &quot;initialized member.&quot; For instance, when using malloc, members are initially uninitialized, but they should receive a value before being used.</p>
<p>However, the <strong>mutable</strong> qualifier temporarily relaxes this rule during the object’s creation process,
allowing modifications even to <code>const</code> members, and allowing a non-nullable pointer to be null
before the object’s initialization completes.</p>

<p>We also have an implicit contract for struct members.
Generally, we assume that members are initialized, but we lack a qualifier to explicitly
indicate &quot;initialized member.&quot;
For instance, when using malloc, members are initially uninitialized, but they should receive a value before being used.</p>

<pre><code class="language-c">struct X * _Opt makeX(const char* name)
{
Expand All @@ -231,17 +277,9 @@ <h4>Non nullable members</h4>
}
</code></pre>

<h5>Transitional State:</h5>

<p>During the object creation (or destruction), the instance is considered to be in a transitional state, where the usual constraints—such as non-nullable pointers and immutability—are lifted. For example, in the <code>makeX</code> function, <code>p-&gt;name</code> can be set to <code>temp</code>, even though <code>name</code> is <code>const</code>. This allows flexibility during initialization, after which the object is returned to its normal state with the contract fully enforced.</p>

<h5>Effect on the Final Object:</h5>

<p>Once the transitional phase is over and the object is returned, the contract that governs the object (such as immutability of <code>name</code> and non-nullability of pointers) is fully reinstated. The <strong>mutable</strong> qualifier only applies within the scope of the constructor or destructor, ensuring that once the object is fully constructed, its state is valid and consistent with the type system’s rules.</p>

<p>This approach allows for more flexibility during object creation while maintaining strong contracts once the object is finalized, enhancing both safety and expressiveness in the code.</p>

<p>OBS: mutable qualifier is not yet implemented in Cake. However, _Opt for structs is implemented.</p>
<blockquote>
<p>OBS: mutable qualifier is not yet implemented in Cake. However, _Opt for structs is implemented and may be replaced in the future</p>
</blockquote>

<h3 id="toc_3">Object lifetime checks</h3>

Expand Down

0 comments on commit d2a3f01

Please sign in to comment.