<story><title>Interview about Austral, a systems programming language with linear types</title><url>https://blog.lambdaclass.com/austral/</url></story><parent_chain><item><author>dgreensp</author><text>As someone working on a language myself, I found this to be very high-quality material!  It aligns with a lot of my thinking, and it’s educational.&lt;p&gt;A random part of interest: I followed the link about how linear types and exceptions don’t mix: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;borretti.me&amp;#x2F;article&amp;#x2F;linear-types-exceptions&quot; rel=&quot;nofollow noreferrer&quot;&gt;https:&amp;#x2F;&amp;#x2F;borretti.me&amp;#x2F;article&amp;#x2F;linear-types-exceptions&lt;/a&gt; In it, the author explains how linear types always need to be explicitly destroyed, and if you end up in a “catch” block, you can’t easily go back and destroy things that are now out of scope, which control flow got interrupted while doing things with.  “Why not just destroy things when they go out of scope?” I thought.  The author addresses this, saying that types that you have to “consume” “at most once” are called affine types, and the compiler can clean them up for you, and it solves the problem with exceptions.  Rust has affine types, and you don’t have to explicitly “destruct” every string&amp;#x2F;object&amp;#x2F;resource using the appropriate destructor for that type, manually, as you do with linear types (of course, the compiler will make sure you do it, but you have to do it).&lt;p&gt;So why does Austral use linear types, not affine types?  The reasons given do not really resonate with me (but I’m not a systems programmer); it’s that the compiler would have to insert hidden function calls, and secondarily, for temporary&amp;#x2F;intermediate values, the order of invocation might not be obvious; plus, maybe the programmer not doing something with a value is a mistake.  I’m really glad the reasons are written out, however.&lt;p&gt;In other areas I feel very aligned with the author, such as on the value of required type annotations and local inference rather than global inference, and I’ve saved the link to refer back to the way the opinion is stated.</text></item></parent_chain><comment><author>_dain_</author><text>&lt;i&gt;&amp;gt;So why does Austral use linear types, not affine types?&lt;/i&gt;&lt;p&gt;Affine types give a &lt;i&gt;safety&lt;/i&gt; guarantee: you can&amp;#x27;t use it more than once. The bad thing (double free, use after free) does not happen.&lt;p&gt;Linear types give that same safety guarantee, plus a &lt;i&gt;liveness&lt;/i&gt; guarantee: you &lt;i&gt;must&lt;/i&gt; use it, possibly in some nontrivial way.&lt;p&gt;A function that takes an affine value as an argument is enforcing a contract about the &lt;i&gt;past&lt;/i&gt; behaviour of the caller, leading up to the call: having the affine value is proof that certain other functions were called in the right way to produce it. But returning an affine value gives you weaker guarantees about &lt;i&gt;future&lt;/i&gt; behaviour, because you can use it zero times. At most you know that it will get Dropped. But maybe you want to enforce more interesting things than the Drop trait can express. Returning a linear value lets you do this: maybe the linear Foo you return can only be disposed of in conjunction with a linear Bar, like&lt;p&gt;&lt;pre&gt;&lt;code&gt;    fn consume(x: Foo, y: Bar) -&amp;gt; Baz
&lt;/code&gt;&lt;/pre&gt;
And perhaps now Baz itself is linear, which has to be consumed in some other way ... at any rate, returning a linear value is proof that in the &lt;i&gt;future&lt;/i&gt;, the program will advance through a particular state machine of function calls, where the states and transitions are defined by the available signatures. If Foo is linear but there&amp;#x27;s no simple function like&lt;p&gt;&lt;pre&gt;&lt;code&gt;    fn drop(x: Foo) -&amp;gt; Unit
&lt;/code&gt;&lt;/pre&gt;
then buckle in, the compiler says you&amp;#x27;re not getting off the ride until it&amp;#x27;s over.</text></comment>
<story><title>Interview about Austral, a systems programming language with linear types</title><url>https://blog.lambdaclass.com/austral/</url></story><parent_chain><item><author>dgreensp</author><text>As someone working on a language myself, I found this to be very high-quality material!  It aligns with a lot of my thinking, and it’s educational.&lt;p&gt;A random part of interest: I followed the link about how linear types and exceptions don’t mix: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;borretti.me&amp;#x2F;article&amp;#x2F;linear-types-exceptions&quot; rel=&quot;nofollow noreferrer&quot;&gt;https:&amp;#x2F;&amp;#x2F;borretti.me&amp;#x2F;article&amp;#x2F;linear-types-exceptions&lt;/a&gt; In it, the author explains how linear types always need to be explicitly destroyed, and if you end up in a “catch” block, you can’t easily go back and destroy things that are now out of scope, which control flow got interrupted while doing things with.  “Why not just destroy things when they go out of scope?” I thought.  The author addresses this, saying that types that you have to “consume” “at most once” are called affine types, and the compiler can clean them up for you, and it solves the problem with exceptions.  Rust has affine types, and you don’t have to explicitly “destruct” every string&amp;#x2F;object&amp;#x2F;resource using the appropriate destructor for that type, manually, as you do with linear types (of course, the compiler will make sure you do it, but you have to do it).&lt;p&gt;So why does Austral use linear types, not affine types?  The reasons given do not really resonate with me (but I’m not a systems programmer); it’s that the compiler would have to insert hidden function calls, and secondarily, for temporary&amp;#x2F;intermediate values, the order of invocation might not be obvious; plus, maybe the programmer not doing something with a value is a mistake.  I’m really glad the reasons are written out, however.&lt;p&gt;In other areas I feel very aligned with the author, such as on the value of required type annotations and local inference rather than global inference, and I’ve saved the link to refer back to the way the opinion is stated.</text></item></parent_chain><comment><author>JonChesterfield</author><text>Linear types are more powerful than affine in terms of implementing code that cannot go wrong as enforced by the type system. State machines reified in application code.&lt;p&gt;Affine is fine if there&amp;#x27;s a catch all operation available for when the value drops out of scope which the compiler inserts. You can call deallocate or similar when an exception comes through the call stack.&lt;p&gt;If the final operation is some function that returns something significant, takes extra arguments, interacts with the rest of the program in some sort of must-happen sense, then calling a destructor implicitly doesn&amp;#x27;t cover it.&lt;p&gt;There&amp;#x27;s some interesting ideas around associating handlers with functions to deal with exceptions passing through but I think I&amp;#x27;ve only seen that in one language. The simple&amp;#x2F;easy approach is to accept that exceptions and linear types are inconsistent.</text></comment>