Using
using confines a resource’s lifetime to a block scope: you hold the resource on entry, and leaving the block automatically calls Dispose. It fits resources that need explicit release — file handles, database connections, transactions.
The Resource Contract: Disposable
The type hosted by using must implement the Disposable protocol, which means providing a parameterless Dispose method. Bring in the protocol with import System.Disposable;:
import System.Disposable;
class FileHandle impl Disposable
{
public var name: string;
init(n: string)
{
name = n;
print("open", name);
}
public func Dispose()
{
print("close", name);
}
}Three Forms
using val r = new Resource(); { } // declare and bind (no semicolon; the block follows immediately)
using name = expr { } // resource binding
using expr { } // expression resourceThe declaration form’s binding is visible inside the block and does not exist outside it. Write constructor arguments directly in new; do not use object initializers: the initializer’s { would be confused with using’s body block.
Nesting and Dispose Order
A using block disposes immediately when it ends; nested blocks dispose in reverse entry order — the last one opened closes first:
using val outer = new FileHandle("database")
{
using val inner = new FileHandle("transaction")
{
print("using", outer.name, "and", inner.name);
}
print("transaction closed, database still open");
}
print("all closed");open database
open transaction
using database and transaction
close transaction
transaction closed, database still open
close database
all closedThe transaction closes the moment the inner block ends, while the database handle stays open until the outer block ends. This order is isomorphic to the last-in-first-out of defer.
The Expression Form
Use the expression form when the resource needs no name: the block cannot reach a reference; the point is purely “paired entry and exit”:
using new FileHandle("temp")
{
print("one-shot resource");
}
print("continue outside the block");open temp
one-shot resource
close temp
continue outside the blockNotes
- The using body must be a block; a standalone
using r;is a syntax error. - Dispose is an ordinary method: a type implementing Disposable can also be disposed by hand, but with using there is no need to manage it manually.
- The deinit destructor is only called as a supplement when a using exits (in reverse base-class order); ordinary block exits do not trigger it, and the scripting version of the language makes no promise about destructor timing.
- A protocol itself can also serve as the resource type (
using val p: P = new R()); Dispose dispatches through the protocol slot to the concrete type, provided the protocol declaration chain carries the Dispose signature.
