<p>Linear types are quite a powerful feature of type systems that ensure that &quot;linear values&quot; are used <em>exactly</em> once.</p>
<p>For example,</p>
<pre><code>fn foo():
    let handle = acquire_linear_value()
    // ...
    close(handle)
</code></pre>
<p>The compiler would force passing <code>handle</code> to some function like <code>close</code> before the function ends; otherwise, <code>handle</code> would <em>not</em> have been used!</p>
<p>This seems fine until other features, which may <em>non</em>-deterministically alter the usual control flow, are introduced in the language. An example of such a feature would be exceptions. E.g.,</p>
<pre><code>fn foo():
    let handle = acquire_linear_value()
    // ...
    bar()      // may throw
    // ...
    close(handle)
</code></pre>
<p>Assuming that <code>bar</code> is a function that may diverge the usual control flow, <code>handle</code> would no longer be guaranteed to be used exactly once.</p>
<p>Can both features coexist in the same language? If so, how?</p>

<control-flow><linear-types><substructural-types>
How do linear types interact with features that may change the normal control flow?
CC BY-SA 4.0
2023-05-18T02:04:03.603Z
maybe take a look at this https://borretti.me/article/linear-types-exceptions
justANewbie
<h1>defer blocks</h1>
<p>Swift has a <code>defer</code> keyword that guarantees a block to run when the scope exits — whether that’s via <code>return</code>, an error, or just reaching the closing brace:</p>
<pre class="lang-swift prettyprint-override"><code>func useFile() throws {
  let handle = open()
  defer {
    close(handle)
  }

  try bar()
  // If bar throws, Swift will catch the error, run the defer block, and then rethrow.

  if checkCondition() {
    return
    // early exit also triggers defer
  }

  baz()
  // reached end of scope normally, defer runs here
}
</code></pre>
<p>If there are multiple <code>defer</code> blocks in the same scope, they run in reverse order of declaration.</p>
<p>In the same vein, languages like C# and JavaScript have try/finally:</p>
<pre class="lang-csharp prettyprint-override"><code>var handle = open();
try
{
  bar();
}
finally
{
  close(handle);
}
</code></pre>

CC BY-SA 4.0
2023-05-18T12:46:25.470Z
2023-05-18T21:59:32.270Z
2023-05-18T21:59:32.270Z
Bbrk24
<h1>A partial solution</h1>
<p>A language like Rust would be able to partially accomplis this. Rust does not have exceptions, which are the primary way that the control flow would be diverted; instead, it has <code>Result</code>-returning functions, which the typechecker can easily see might lead to the linear type never being used. Rust does, however, have panics; in that case we will just have to assume that whatever the linear type represents will be taken care of by the OS (like if it's a file handle the OS will close it). This is not a perfect solution, however.</p>

CC BY-SA 4.0
2023-05-18T12:30:58.917Z
2023-05-18T12:30:58.917Z
Ginger
# How do linear types interact with features that may change the normal control flow?
Posted by: username_0 on 2023-05-18
Linear types are quite a powerful feature of type systems that ensure that "linear values" are used exactly once.
For example,
fn foo():
    let handle = acquire_linear_value()
    // ...
    close(handle)

The compiler would force passing handle to some function like close before the function ends; otherwise, handle would not have been used!
This seems fine until other features, which may non-deterministically alter the usual control flow, are introduced in the language. An example of such a feature would be exceptions. E.g.,
fn foo():
    let handle = acquire_linear_value()
    // ...
    bar()      // may throw
    // ...
    close(handle)

Assuming that bar is a function that may diverge the usual control flow, handle would no longer be guaranteed to be used exactly once.
Can both features coexist in the same language? If so, how?
**Tags:** control-flow linear-types substructural-types
> **Comments:**
> **username_1**: maybe take a look at this https://borretti.me/article/linear-types-exceptions  
---
## 2 answers
### Answer by username_2 on 2023-05-18. Score: 6
defer blocks
Swift has a defer keyword that guarantees a block to run when the scope exits — whether that’s via return, an error, or just reaching the closing brace:
func useFile() throws {
  let handle = open()
  defer {
    close(handle)
  }

  try bar()
  // If bar throws, Swift will catch the error, run the defer block, and then rethrow.

  if checkCondition() {
    return
    // early exit also triggers defer
  }

  baz()
  // reached end of scope normally, defer runs here
}

If there are multiple defer blocks in the same scope, they run in reverse order of declaration.
In the same vein, languages like C# and JavaScript have try/finally:
var handle = open();
try
{
  bar();
}
finally
{
  close(handle);
}
---
### Answer by username_3 on 2023-05-18. Score: 3
# A partial solution

A language like Rust would be able to partially accomplis this. Rust does not have exceptions, which are the primary way that the control flow would be diverted; instead, it has `Result`-returning functions, which the typechecker can easily see might lead to the linear type never being used. Rust does, however, have panics; in that case we will just have to assume that whatever the linear type represents will be taken care of by the OS (like if it's a file handle the OS will close it). This is not a perfect solution, however.
---
