Monades

Monades

A brief dive into the Pony programming language

November 2nd, 2017

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:

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

Stats


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

by Roberto Dip

Web Developer passionate about OSS