Developing concurrent programs with Pony
Horse Power
Pony, an object-oriented programming language with static typecasting, trots down well-mapped paths to deliver secure, high-performance code for concurrent applications.
The still young Pony [1] programming language uses the actor model [2] and capabilities [3] to make deadlocks and data races things of the past. In this article, I take Pony for a test ride with an example application that, once it has compiled successfully, logs the consumption of paint and reports the results in a single line.
Figure 1 revisits the problems of concurrent programming in C and C++. To improve performance, the hypothetical program outsources tasks to concurrent threads that access the shared memory area. Locks manage access to prevent different threads editing data simultaneously, falsifying each other's results in the process, and generating race conditions. Nothing good results when programming errors interact and create deadlocks.
Table 1 summarizes the problems associated with implementation across various languages. The comparison with Java is inevitable, because the language offers one of the most successful enhancements of the C and C++ method. A comparison with Rust [4] is also appropriate, because the new kid in town also tries to generate secure and fast code for concurrent applications.
Table 1
Feature Comparison
Language Feature | C/C++ | Java | Rust | Pony |
---|---|---|---|---|
AoT Compilation |
Yes |
No* |
Yes |
Yes |
Memory Secure |
No |
Yes |
Yes |
Yes |
Type Secure |
No |
Yes |
Yes |
Yes |
Avoids Race Conditions |
No |
No |
Yes |
Yes |
Avoids Deadlocks |
No |
No |
No |
Yes |
Actor-Based |
No |
No |
No |
Yes |
*Officially as of Java 9 [5]. |
||||
Except for dynamic loading of classes [6]. |
Both Pony and Rust compile programs ahead of time (AoT) to create executable binary code. The method saves time because the languages identify and rule out type conflicts in advance. Java, on the other hand, usually first converts source code to non-executable bytecode, which a virtual machine (VM) executes and monitors. Pony and Java both leave memory management to a garbage collector, which Pony integrates into the run-time environment of the compiler results because it lacks a VM.
Actor Model
Pony programs are always free of data races and deadlocks through the agency of actors. As Figure 2 shows, the model does without a shared memory area and therefore does not need to use locks. Because internally the threads (aka actors) work sequentially, data races could theoretically still occur between the competing actors; however, applications mutually exchange application data through asynchronous communications. The sender deletes all pointers to variable data before sending, which also successfully prevents data races in this scenario.
Behaviors (asynchronous functions) are used as mailboxes for incoming messages, which Pony calls like normal methods but runs asynchronously. The actor thus continues its work sequentially. The Pony developers did not create the actor model; the programming languages Erlang, Io, D, and Scala also use it.
Installation
The current release of Pony [7] can be installed using the commands in Listing 1 on a 64-bit Debian system. The first line integrates the packet source into the /etc/apt/sources.list
file. The second line updates the Debian package database, and the third line installs Pony. There is no Debian package for the i386 architecture; a manual compile is needed in this case.
Listing 1
Installation on Debian 8
Listing 2 shows the directory tree of the sample application. If you change to the project directory and compile the program with ponyc
, the result is the binary executable, as shown in Figure 3, which you can launch with the ./blue-horses
command.
Listing 2
The .pony Files
The main.pony
file is the entry point for the Pony program (Figure 4). It uses the class from the resource.pony
file to create paint stocks for the primitives (colors) from primitives.pony
and presents these to the actor of the Painter
type from painter.pony
. The actor processes the quantity of paint and reports its consumption in the form of a report to main.pony
.
Classes
Pony summarizes application data in classes, as the Resource
class illustrates in the example in Listing 3, which stores paint types and their respective stock. The class
keyword introduces the class in line 1, and line 2 declares the public field name
of the user-defined Paint
type, which line 6 in Listing 4 again picks up. Thanks to the let
keyword, the field can only be written to once, in contrast to a field initiated as var
. The class stores the paint types and the respective stock.
Listing 3
resource.pony
Listing 4
primitives.pony
Line 3 of Listing 3 defines the private _amount
field as an integer data type and sets its value to
. Private field names are prefixed by an underscore, and only the owning class instance can access them. The constructor of the Resource
class introduces the new
keyword in line 5. The parameter list follows in create()
. The name'
variable field is a pointer to an object of the Paint
type. The next line then saves the name
field permanently as an instance of the class.
The fun
keyword introduces the method declarations for level()
and fill()
(lines 8 and 11). If the parameter list is followed by a colon, the type of the return value follows. For level()
, it is integer type U64
from the private _amount
field.
The value of the expression in the last line of a method is usually its return value, although the use of return
lets developers close methods prematurely. The fill()
method (line 11) increments the value of _amount
by 1
.
Because of the ref
specification in line 11, the method requires write access for a pointer to an instance of the Resource
class. These rights are granted by reference capabilities, which I talk about later; however, before I get to that, I'll look at primitives, which are similar to classes.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs
-
Juno Computers Launches Another Linux Laptop
If you're looking for a powerhouse laptop that runs Ubuntu, the Juno Computers Neptune 17 v6 should be on your radar.
-
ZorinOS 17.1 Released, Includes Improved Windows App Support
If you need or desire to run Windows applications on Linux, there's one distribution intent on making that easier for you and its new release further improves that feature.
-
Linux Market Share Surpasses 4% for the First Time
Look out Windows and macOS, Linux is on the rise and has even topped ChromeOS to become the fourth most widely used OS around the globe.
-
KDE’s Plasma 6 Officially Available
KDE’s Plasma 6.0 "Megarelease" has happened, and it's brimming with new features, polish, and performance.
-
Latest Version of Tails Unleashed
Tails 6.0 is based on Debian 12 and includes GNOME 43.
-
KDE Announces New Slimbook V with Plenty of Power and KDE’s Plasma 6
If you're a fan of KDE Plasma, you'll be thrilled to hear they've announced a new Slimbook with an AMD CPU and the latest version of KDE Plasma desktop.
-
Monthly Sponsorship Includes Early Access to elementary OS 8
If you want to get a glimpse of what's in the pipeline for elementary OS 8, just set up a monthly sponsorship to help fund its continued existence.