A primitive is similar to a class, but there are two critical differences:

  1. A primitive has no fields.
  2. There is only one instance of a user-defined primitive.

Having no fields means primitives are never mutable. Having a single instance means that if your code calls a constructor on a primitive type, it always gets the same result back (except for built-in "machine word" primitives, covered below).

What can you use a primitive for?

There are three main uses of primitives (four, if you count built-in "machine word" primitives).

  1. As a "marker value". For example, Pony often uses the primitive None to indicate that something has "no value". Of course, it does have a value, so that you can check what it is, and the value is the single instance of None.
  2. As an "enumeration" type. By having a union of primitive types, you can have a type-safe enumeration. We'll cover union types later.
  3. As a "collection of functions". Since primitives can have functions, you can group functions together in a primitive type. You can see this in the standard library, where path handling functions are grouped in the primitive Path, for example.

Primitives are quite powerful, particularly as enumerations. Unlike enumerations in other languages, each "value" in the enumeration is a complete type, which makes attaching data and functionality to enumeration values easy.

Built-in primitive types

The primitive keyword is also used to introduce certain built-in "machine word" types. Other than having a value associated with them, these work like user-defined primitives. These are:

  • Bool. This is a 1-bit value that is either true or false.
  • ISize, ILong, I8, I16, I32, I64, I128. Signed integers of various widths.
  • USize, ULong, U8, U16, U32, U64, U128. Unsigned integers of various widths.
  • F32, F64. Floating point numbers of various widths.

ISize/USize correspond to the bitwidth of the native type size_t, which varies by platform. ILong/ULong similarly correspond to the bitwidth of the native type long, which also varies by platform. The bitwidth of a native int is the same across all the platforms that Pony supports, and you can use I32/U32 for this.

Primitive initialisation and finalisation

Primitives can have two special functions, _init and _final. _init is called before any actor starts. _final is called after all actors have terminated. The two functions take no parameter. The _init and _final functions for different primitives always run sequentially.

A common use case for this is initialising and cleaning up C libraries without risking untimely use by an actor.

results matching ""

    No results matching ""