Pony’s type system is what makes it special. There’s plenty to love about it otherwise but, in the end, it’s the type system that contains much of what makes Pony novel. In this chapter, we are going to explore the basics of the type system. If you worked with a statically typed language before, there shouldn’t be anything surprising to you. By the time you’ve finished this chapter, you should have a handle on basics of the Pony type system.
Static vs Dynamic: What’s the difference? In both kinds of language, your data has a type. So what’s the difference?
With a dynamically typed language, a variable can point to objects of different types at different times.
Just like other object-oriented languages, Pony has classes. A class is declared with the keyword class, and it has to have a name that starts with a capital letter, like this:
class Wombat Do all types start with a capital letter? Yes! And nothing else starts with a capital letter. So when you see a name in Pony code, you will instantly know whether it’s a type or not.
A primitive is similar to a class, but there are two critical differences:
A primitive has no fields. 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?
An actor is similar to a class, but with one critical difference: an actor can have behaviours.
Behaviours A behaviour is like a function, except that functions are synchronous and behaviours are asynchronous. In other words, when you call a function, the body of the function is executed immediately, and the result of the call is the result of the body of the function. This is just like method invocation in any other object-oriented language.
Like other object-oriented languages, Pony has subtyping. That is, some types serve as categories that other types can be members of.
There are two kinds of subtyping in programming languages: nominal and structural. They’re subtly different, and most programming languages only have one or the other. Pony has both!
Nominal subtyping This kind of subtyping is called nominal because it is all about names.
If you’ve done object-oriented programming before, you may have seen a lot of discussion about single inheritance, multiple inheritance, mixins, traits, and similar concepts.
A struct is similiar to a class. There’s a couple very important differences. You’ll use classes throughout your Pony code. You’ll rarely use structs. We’ll discuss structs in more depth in the C-FFI chapter of the tutorial. In the meantime, here’s a short introduction to the basics of structs.
Structs are “classes for FFI” A struct is a class like mechanism used to pass data back and forth with C code via Pony’s Foreign Function Interface.
A type alias is just a way to give a different name to a type. This may sound a bit silly: after all, types already have names! However, Pony can express some complicated types, and it can be convenient to have a short way to talk about them.
We’ll give a couple examples of using type aliases, just to get the feel of them.
Enumerations One way to use type aliases is to express an enumeration.
The types we’ve talked about so far can also be combined in type expressions. If you’re used to object-oriented programming, you may not have seen these before, but they are common in functional programming. A type expression is also called an algebraic data type.
There are three kinds of type expression: tuples, unions, and intersections.
Tuples A tuple type is a sequence of types. For example, if we wanted something that was a String followed by a U64, we would write this: