Skip to main content

newtype

A nominal single-field wrapper, distinct from the type it wraps: no conversion runs in either direction, and two newtypes over one underlying type are not interchangeable.

newtype Altitude { value: int32; }

const cruise: Altitude = Altitude{ 1200 };
const raw: int32 = cruise.value;

Declaration​

A newtype body declares exactly one field, and may close with a run of assert invariants over that field.

  • A newtype declares one field, no more and no fewer.
  • The body admits that field and then assertions, so a second field does not parse.
  • The field type may be any type.
  • Assertions follow the field and are checked at construction, under a struct's rules.
  • The name is a global declaration, unique among the file's declarations.
newtype Altitude {
    value: int32;

    assert above_ground = value >= 0;
}

newtype TrackIds { values: uint32[]; }

Values​

Construction is Path { expr } — the value alone, with no field name and no =. Unwrapping is a member access on the field name.

  • The expression must be assignable to the field type.
  • A newtype value is not assignable to the underlying type, and the underlying type is not assignable to the newtype. Altitude and int32 are unrelated types.
  • Two newtypes over one underlying type are not interchangeable either, which is what makes a newtype worth declaring over a type alias.
  • Equality is defined between values of the same newtype, comparing what they wrap.
newtype Altitude {
    value: int32;

    assert above_ground = value >= 0;
}

const cruise: Altitude = Altitude{ 1200 };

cruise.value                  // => 1200
cruise == Altitude{ 1200 }    // => true
try(Altitude{ -5 })           // => none

Errors​

Field bindings in place of a value​

A struct literal names its fields; a newtype literal holds the wrapped value alone.

newtype Altitude { value: int32; }

const cruise: Altitude = Altitude{ value = 1200; };   // error: newtype-value-syntax

A wrapped value of the wrong type​

newtype Altitude { value: int32; }

const cruise: Altitude = Altitude{ "high" };   // error: newtype-value-type

The underlying type in place of the newtype​

newtype Altitude { value: int32; }

const cruise: Altitude = 1200;    // error: type-mismatch
const raw: int32 = Altitude{ 1200 };   // error: type-mismatch

A literal whose target is neither a struct nor a newtype​

An alias is not a wrapper, so it has neither fields to bind nor a value to hold.

type Altitude = int32;

const cruise: Altitude = Altitude{ value = 1200; };   // error: not-a-struct-or-newtype
  • type-alias — the transparent alternative, which introduces no new type.
  • struct — the multi-field record, and the source of the assertion rules.