This post was originally published on monades.roperzh.com
Pony is an emerging programming language which is described by its authors as "an open-source, object-oriented, actor-model, capabilities-secure, high-performance programming language."
Wording aside, this article focuses on the most interesting aspects of the language itself and how the code looks like.
Compiled
Pony inhabits in the reigns of compiled languages, when executing the ponyc
command (which is part of the Pony installation) the compiler creates an executable with the same name of the current folder.
$ cd myprogram
$ ponyc
$ ./myprogram
Statically typed
A lot of the guarantees that Pony offers (no exceptions at runtime, secure capabilities and more) are backed up by its type system. If you miss a type or assign a value to a variable of a different type, the compiler complains and stops the compilation.
The syntax to denote a type is variable: Type
.
class Hello
// name is a variable of type String
let name: String
// age is a variable of type U64
let age: U64
// the argument name' is a variable of type string
new create(name': String) =>
name = name'
However, in certain scenarios, types are inferred by the compiler. Here, for example, the type of the hello
variable can be safely omitted.
let hello = Hello("Seneca")
Object oriented
Pony is object-oriented and exposes it with classes. A class is declared with the keyword class
, and can have:
- One or many constructors differentiated by name
- Fields
- Functions
Unlike many other OOP languages, Pony doesn't have the concept of inheritance, instead it embraces traits and interfaces.
class Book
// Fields of a given class are defined
// like this.
// - `var` fields can be asigned multiple times
// - `let` fields can only be assigned once in the constructor.
// - fields starting with underscore are private
let author: String
var _editions: U32
new create(author': String, editions': U32) =>
author = author'
_editions = editions'
// A class can have functions
fun get_author(): String => author
fun get_editions(): U32 => _editions
// To set values, is necessary to mark
// the function as `ref`
fun ref set_editions(to: U32) => _editions = to
Actor Model
Pony embraces the Actor Model and supports it out of the box. If you haven't heard of it, and you're interested, feel free to check out Get to Know the Actor Model.
In the Pony world, actors are similar to classes, with the only difference that they are asynchronous entities. Instead of functions an actor has behaviors; when called, the body of a behavior is not executed syncronously, instead, it will be executed at some indeterminate time in the future.
use "promises"
actor Writer
// As with classes, you can define fields
let name: String
// And constructors too!
new create(name': String) =>
name = name'
// Instead of functions, an Actor has behaviors
be get_name(promise: Promise[String]) => promise(name)
Communicating with Actors
Hence the asynchronous nature of actors, Pony also comes with primitives to enable asynchronous communication through Promise
s. A Promise
represents a value that will be available at a later time. Promise
s are either fulfilled with a value or rejected. If you're interested in the details of Pony promises, there's an excellent blog post by Kevin Hoffman on the subject.
// Create a new Actor
let writer = Writer("Italo Calvino")
// Create a new promise
let promise = Promise[String]
// Invoke the Actor behavior, providing a
// promise to be fulfilled
writer.get_name(promise)
// Print the value of the promise when fullfilled
// using a partial application of `env.out.print`
promise.next[None](env.out~print())
PonyTest
Pony comes with the PonyTest
package which provides a simple unit testing framework: each unit test is a class, with a single test function, and by default, all tests run concurrently.
use "ponytest"
actor Main is TestList
new create(env: Env) =>
PonyTest(env, this)
fun tag tests(test: PonyTest) =>
test(_TestAdd)
class iso _TestAdd is UnitTest
fun name():String => "addition"
fun apply(h: TestHelper) =>
h.assert_eq[U32](4, 2 + 2)
Interesting facts
- You integrate Pony with C through the Foreign Function Interface (FFI)
- Division by zero is allowed, and results in zero
-
a = b
is an expression that returns the old value ofa
Stats
- ~5 years of life, first commit at Nov 9, 2012
- 4,549 commits
- 46 releases
- 104 contributors
- 2,672 GitHub stars
-
76 questions tagged with
pony
in StackOverflow
note: this numbers date of 10/31/2017, they become more and more invalid as time goes on; moreover, they don't represent anything significant and are included only for fun.
Top comments (6)
Ooooh thanks for this.
Really seems to me like if Ruby and JavaScript become a single language.
I hope one day it becomes a language where big corporations require it for jobs:
It's more like if you took Erlang and Ruby and rammed them together at high speed.
Having used it a fair bit myself, I can say that it does the OOP and Actor things better, and, barring compiler bugs, it produces safer, more secure, more reliable programs.
I don't get the actor programmation thing..
But this look good.
Which part? Actors with message passing give you ways to model your program with partial failures, for example, imagine worker Rabbitmq deals with it being down, rest of the program still works. You can create spin up workers with specific tasks and if they crash, rest of the system still works. It's a whole different way of having things working concurrently.
I'm "novice" in programming. I've learn with Symfony and I don't really know RabbitMq.
It look like Functionnal programming in my head. One thing that I also can't get..