loading...
Cover image for A brief dive into the Pony programming language

A brief dive into the Pony programming language

roperzh profile image Roberto Dip Originally published at monades.roperzh.com on ・4 min read

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 Promises. A Promise represents a value that will be available at a later time. Promises 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 of a

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.

Resources

Posted on by:

roperzh profile

Roberto Dip

@roperzh

Hello! I'm @roperzh. Functional programming, JavaScript, Elixir, and Ruby makes me excited. I like to contribute to OSS and write about programming and life. Simplicity is my motto.

Discussion

pic
Editor guide
 

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:

Seeking senior software engineer: Must have 5+ years of experience with Pony

 

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..