Like my last post on ATS , this is far from a full-fledged tutorial, but I think it will nonetheless be instructive to students of ATS.

# Linear Types

Linear types are a relatively unfamiliar feature to most programmers; Rust is the only mainstream language that has them, but ATS gives the programmer finer control of how linear types, allowing the programmer to construct their own linear types in much the same way as ordinary types in an ML.

Linear types in this example accomplish essentially what is accomplished in Rust - they allow us to safely skirt garbage collection where performance is absolutely critical.

### Example: Consuming Errors

To again use a "real world" example from polyglot, suppose we wish to count the number of lines in a file.

// Takes as an argument a string containing the full path to a file.
fun line_count(s: string): int =
let
var ref = fileref_open_opt(s, file_mode_r)
in
case+ ref of
| ~None_vt() => (println!("Warning: could not open file at " + s) ; 0)
| ~Some_vt(x) =>
begin
let
var viewstream: stream_vt(string) = \$EXTRA.streamize_fileref_line(x)
var n: int = stream_vt_length(viewstream) - 1
val _ = fileref_close(x)
in
n
end
end
end

This will be mostly familiar to anyone with a Haskell background - Some corresponds to Just, and None to Nothing. But here we are matching on a value with constructor Some_vt rather than Some, and for some reason prepending ~ to the constructors.

This is because fileref_open_opt returns a value with a linear type. Option_vt is just like Option, except that it must always be consumed in the scope that it is created. Linear types allow us to precisely pinpoint where a value is needed, eliminating the need for garbage collection (as in Rust). In this example, linear types force us to handle the error - the ~ in the pattern match tells the compiler "immediately free the memory after the right-hand side executes". Had we replaced the pattern ~Some_vt(x) with _, we would have seen a type error.

In practice, this means that we will be much more careful to avoid spurious computation, e.g. filling a list_vt(a) with values we don't need. Haskell has laziness to avoid spurious computation, but it cannot benefit from unboxed data types at the same time. ATS is to my knowledge the only language that can offer both guarantees.