Skip to content
LogoLogo

Nominal types

type tokenId is uint declares a new type that is stored and encoded as a uint, but that the type checker keeps apart from uint and from every other type over uint.

nominal-types.lithe
(* `type x is T` makes a new type with T's representation. It does not mix with T,
   or with other types over T, without an explicit conversion. *)
 
import "std/evm";
 
type BasisPoints is uint16;
type TokenId is uint;
type OrderId is bytes32;
 
storage is record {
  fee : BasisPoints;
  owners : map(TokenId, address);
}
 
external function setFee(const fee : BasisPoints) is {
  storage.fee := fee;
}
 
external function claim(const id : TokenId) is {
  storage.owners[id] := Evm.sender();
}
 
(* Convert out with the underlying type's name, and in with the new type's name. *)
external view function feeOn(const amount : uint) : uint is
  amount * uint(uint16(storage.fee)) / 10_000
 
external pure function next(const id : TokenId) : TokenId is
  TokenId(uint(id) + 1)

Binding a raw uint to a tokenId is a compile error:

initializer type does not match its annotation

Integer literals take on nominal types directly: const fee : BasisPoints := 500;.