At QCon London 2016 I saw a presentation on Pony and my interest was peaked enough to take a closer look at the language. In this article I will try to contrast Pony against my current favorite language, Go. (I will leave it to others to compare Pony with Erlang or Elixir)
Similarities with Go
Let’s start off by listing some of the characteristics shared between Go and Pony:
- Ahead-of-time (AOT) compiled
- Composition over inheritance
- Garbage collected
- Hard to Google
- Inherent build system
- Open Source
- Statically typed
- Structurally typed interfaces
- Mostly insignificant whitespace
How is it different from Go?
- Actor based concurrency (Mailboxes!)
- Algebraic type expressions (Union types!)
- Classes (composed of fields, constructors, and functions)
- Default argument values
- Erlang style Pattern Matching
- Expressions with more than one infix operator must use parentheses to remove the ambiguity
- Fully concurrent GC with no stop-the-world or sweep phase (Go GC is concurrent since 1.5)
- Generics
- Implicit return values (last expression)
let
in addition tovar
- No
null
(but it has aNone
type) - No deadlocks (since there are no locks at all)
- No global variables (Go has package global variables)
- Not possible to have data-races (ensured by the compiler)
- User defined primitive types (like a class, but has no fields and there is only one instance)
- Statements are expressions
- Three kinds of type expressions: tuples, unions, and intersections
- Trait system (similar to Java 8 interfaces that can have default implementations)
- Type annotations to indicate capabilities (Rcaps)
- Type aliases (enumerations, complex types)
- ~zero overhead when calling out to C
Installing Pony
If you are using OS X and have Homebrew installed, then you can install Pony like this:
$ brew install ponyc
The current version of ponyc
as of this writing is 0.2.1.
Make sure you also get the pony-vim-syntax.
Hello, World!
The entry point of a Pony binary is the Main
actor. The binary is named after the directory, just like how it works in Go.
ponyhello/main.pony
actor Main
new create(env: Env) =>
env.out.print("Hello, World!")
And as you probably know, the Go entry point is the main
func.
gohello/main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Actors
The concurrency in Pony is based on Actors, just like in Erlang. Actors in Pony can, unlike classes, have behaviours (asynchronous methods)
Behaviours are asynchronous, but actors themselves are sequential. Actors will only execute a single behaviour at the same time.
Classes
A class in Pony can have multiple named constructors. Every constructor has to set every field in an object.
The underscore (_
) is used to make something private in Pony.
(Exported identifiers in Go start with a upper case letter)
mascot/main.pony
actor Main
let mascot: Mascot
new create(env: Env) =>
mascot = Mascot("Go gopher")
env.out.print(mascot.message())
class Mascot
let _name: String
new create(name: String) =>
_name = name
fun message(): String =>
"The " + _name + " is the best mascot!"
Learn more about Pony
- Pony Language
- Pony Tutorial
- Pony Compiler
- Deny Capabilities for Safe, Fast Actors
- My Little Pony - Codemesh 2015
Bonus: Linking to the shared library from the article Go and Ruby-FFI
Pony includes a really nice C FFI library and this is an example of how you can use it:
use "path:."
use "lib:sum"
use @add[I64](a: I64, b: I64)
actor Main
new create(env: Env) =>
env.out.print("4+8 = " + @add(4,8).string())
Then you just need to compile your binary by calling ponyc