owned

owned (along with shared) manage the deallocation of a class instance. owned is meant to be used when only one reference to an object needs to manage that object's storage.

Using owned

To use owned, use the owned keyword when allocating a class instance, as shown in this example:

class MyClass { }

var myOwnedObject = new owned MyClass();

When myOwnedObject goes out of scope, the class instance it refers to will be deleted.

Copy initializing from myOwnedObject or assigning it to another owned will leave myOwnedObject storing a nil value and transfer the owned class instance to the other value.

var otherOwnedObject = myOwnedObject;
// now myOwnedObject stores nil
// the value it stored earlier has moved to otherOwnedObject

myOwnedObject = otherOwnedObject;
// this assignment moves the value from the right-hand-side
// to the left-hand-side, leaving the right-hand-side empty.
// after the assignment, otherOwnedObject stores nil
// and myOwnedObject stores a value that will be deleted
// when myOwnedObject goes out of scope.

It is possible to transfer the ownership to another owned variable before that happens.

owned forms part of a type and can be used in type expressions:

var emptyOwnedObject: owned MyClass;

Borrowing from owned

The owned.borrow method returns the pointer managed by the owned. This pointer is only valid as long as the owned is storing that pointer.

The compiler includes a component called the lifetime checker that can, in many cases, check that a borrow does not refer to an object that could be deleted before the borrow. For example:

proc test() {
  var a: owned MyClass = new owned MyClass();
  // the instance referred to by a is deleted at end of scope
  var c: borrowed MyClass = a.borrow();
  // c "borrows" to the instance managed by a
  return c; // lifetime checker error! returning borrow from local variable
  // a is deleted here
}

Coercions for owned

The compiler includes support for introducing automatic coercions from owned to the contained class type. This is equivalent to calling the owned.borrow method. For example:

proc f(arg:MyClass) {
  writeln(arg);
}

var myOwned = new owned MyClass();
f(myOwned); // compiler coerces to MyClass via borrow()

Additionally, the compiler includes support for coercing a value of type owned T to owned U when T is a subclass of U. For example:

class Person { }
class Student : Person { }

var myStudent = new owned Student();
var myPerson:owned Person = myStudent;
// relies on coercion from owned Student to owned Person
// moves the instance from myStudent to myPerson, leaving
// myStudent containing nil.

owned Intents and Instantiation

The default intent for owned currently depends on whether or not the formal argument was declared with a type.

If the formal argument has a declared type, the default intent is in, meaning that ownership will occur.

var global: owned MyClass;
proc saveit(arg: owned MyClass) {
  global = arg; // OK! Transfers ownership from 'arg' to 'global'
  // now that instance will be deleted at end of program
}
proc test0() {
  var x = new owned MyClass();
  saveit(x);
  // now x stores `nil` since ownership was transfer to the argument
}

If the formal argument had no type (i.e. it is generic) and used const or default intent, the argument will not cause ownership transfer and the function will be instantiated with the borrow type if an owned actual is supplied. For example:

proc f(x) {
  writeln("in f, x.type is ", x.type:string);
}
proc test1() {
  writeln("in test1");
  var x = new owned MyClass();
  f(x); // f gets a borrow
  writeln("back in test1");
  writeln(x); // so x is not 'nil' at this point
}

Note

It is expected that this rule will change in the future with more experience with this language design.

record owned

owned manages the deletion of a class instance assuming that this owned is the only thing responsible for managing the lifetime of the class instance.

proc init(type t)

Default-initialize a owned to store type t

proc init(p: unmanaged)

Initialize a owned with a class instance. When this owned goes out of scope, it will delete whatever class instance it is storing.

It is an error to directly delete the class instance while it is managed by a owned.

Arguments:p -- the class instance to manage. Must be of unmanaged class type.
proc init(p: ?T)
proc init=(ref src: owned)

Copy-initializer. Creates a new owned that takes over ownership from src. src will refer to nil after this call.

proc deinit()

The deinitializer for owned will destroy the class instance it manages when the owned goes out of scope.

proc ref clear()

Empty this owned so that it stores nil. Deletes the previously managed object, if any.

proc ref retain(newPtr: unmanaged t)

Change the instance managed by this class to newPtr. If this record was already managing a non-nil instance, that instance will be deleted.

Here t refers to the object type managed by this owned.

proc ref release(): unmanaged t

Empty this owned so that it manages nil. Returns the instance previously managed by this owned.

Here t refers to the object type managed by this owned.

proc borrow()

Return the object managed by this owned without impacting its lifetime at all. It is an error to use the value returned by this function after the owned goes out of scope or deletes the contained class instance for another reason, such as with = or :proc`retain`. In some cases such errors are caught at compile-time.

proc =(ref lhs: owned, ref rhs: owned)

Assign one owned to another. Deletes the object managed by lhs, if any. Transfers ownership of the object managed by rhs to lhs, leaving lhs storing nil.

proc <=>(ref lhs: owned ?t, ref rhs: owned t)

Swap two owned objects.

type Owned = owned

This type allows code using the pre-1.18 Owned record to continue to compile. It will be removed in a future release.