The ‘manage’ statement¶
The manage
statement provides a mechanism for performing actions
automatically at the beginning and end of a scope.
The syntax of the manage
statement is inspired by its Python
counterpart. The main difference is the use of the manage
keyword to open the statement instead of with
:
manage myManager() as myResource do
myResource.doSomething();
The manage
statement accepts a manager (the myManager() call
in the above example). The statement calls a special method on the
manager which lets it perform actions before executing the managed
block. For a type to be recognized as a valid manager, it must
implement the contextManager
interface.
The manager may optionally return a resource. If a developer wants
to make use of the resource, they may capture it after the manager
expression (the myResource declaration in the above example).
The resource may be of any type, and is the value returned by the
special method called enterContext()
.
Any aggregate type may be used as a manager as long as it implements the
contextManager
interface, which requires implementing two methods
called enterContext()
and exitContext()
:
record myManager : contextManager {
var x: int = 0;
proc enterContext() ref: int {
writeln('x is: ', x);
return x;
}
proc exitContext(in err: owned Error?) {
if err then halt(err:string);
writeln('x is: ', x);
}
}
var m = new myManager();
manage m as myResource {
// Prints '0'
myResource = 8;
// Prints '8'
}
The enterContext()
method is called on the manager before entering
the managed block. The exitContext()
method is called on the
manager before leaving the block. It accepts a nilable
owned Error?
by in
intent in order to take ownership of it.
The type author may decide to rethrow the error or suppress it.
Status and Future Work¶
The behavior of several aspects of the manage
statement have yet
to be formalized, such as:
If multiple overloads of
enterContext()
exist that have different return intents, it is unclear what the disambiguation order used to select an overload should be.It is uncertain whether or not the storage kind (e.g.
var
) of a resource should be allowed to be explicitly specified. For example:manage foo as var bar do writeln(bar);
Should explicit declaration of the
var
storage kind for bar be allowed?It is unclear how the
exitContext()
method of a manager should interact with errors beyond guaranteeing thatexitContext()
is called even if an error is thrown from within a managed block.The names of the special methods
enterContext()
andexitContext()
are unstable and subject to change.