Pony is an object-oriented language. Data and behavior are co-located in classes and actors. However, Pony’s OO is different than the OO you might be used to. Pony favors composition over inheritance.
What does it mean to favor composition over inheritance? Well, for starters, Pony has no inheritance. When you favor composition over inheritance, you favor “has-a” relationships over “is-a” relationships.
“is-a” relationships are the common starting point for teaching object-orientation. If you are reading this after writing some Pony, you know that Pony makes expressing such relationships more difficult. We’ll leave the discussion of why to another time.
In this chapter, we are going to explore ways to “share” and “reuse” code in Pony. We are also going to look at patterns you can follow to implement reuse and code organization methods that you’ve used in other languages.
Some of those patterns are ones that you commonly see to allow code reuse via “is-a” relationships. Just because Pony favor composition, doesn’t mean that some of those inheritance tricks that you might know and love are unavailable to you. You will, however, need to keep an open mind and approach them a little differently than you are used to.
In this chapter we’ll cover…
A callback based approach that allows you to create mini-frameworks allowing for specialization of your code. The notifier pattern is used throughout the Pony standard library.
Pony doesn’t do inheritance, but with default implementations for traits and interfaces you can get pretty close.
The mixin pattern is like the inheritance pattern but “even more so”. If you are looking for a full-on Java-style “class A extends class B” type experience, then the mixin pattern is what you are looking for.
Does your favorite language have bare functions of some sort? Do you wish Pony had bare functions or perhaps… global functions? If so, the global function pattern is for you.
Problem You need to specialize an actor so that at certain times during its life-cycle, you can take an appropriate action. For example, all TCP connections are fundamentally the same but, what they do at certain points like:
when opened sending data receiving data when closing will need to change based on “the type” of TCP connection in question.
Actor specialization arises often when you want to create reusable Pony code.
Problem You want to share code between classes (or actors), but Pony doesn’t allow you to inherit from other classes. What’s an enterprising programmer to do? Pony is object-oriented and object-orientation means inheritance via classes, right?
Pony believes in “composition over inheritance” so, inheritance as you might be familiar with it isn’t available. However, this doesn’t mean that you can’t share implementation across differing types. Enter default implementations on traits and interfaces.
Problem You have some common logic that you want to share between classes (or actors). You could use the “inheritance pattern”, however, if your logic is stateful and needs to access fields, it won’t work. What you probably want is something akin to “mixins”. Pony doesn’t directly support mixins, however, you can emulate them fairly easily.
Solution Creating a “mixin like” thing in Pony is pretty straightforward. If you checked out the inheritance pattern, then you’ve already seen most of the mixin pattern in action.
Problem Your design calls for a global function, but Pony doesn’t have them.
Solution Use a primitive.
primitive Doubler fun apply(U64: num): U64 => num * 2 Discussion Primitives serve a couple of different purposes in Pony. Here, we are using a primitive like a global function. Any place in our codebase, we can use Doubler like so:
Doubler(U64(1)) Regular Pony package rules still apply, so the package that Doubler is a part of needs to be imported, but otherwise, you can use a primitive with an apply method much as you would global functions in a language like C.