Developing concurrent programs with Pony
Primitives
Primitives are classes without fields. Only one instance exists for them, much like none
and null
in other languages. Listing 4 begins by declaring the methodless primitives Amber
, Blue
, Crimson
, and Other
symbolically as the paint types used. Line 6 combines the four primitives using type
to create the Paint
alias, Color
.
In contrast, the Properties
primitive group functions in the form of methods – more specifically, the two helper methods list()
and name()
. The first returns all the paints in a field; the second returns the name of the paint as a string for the primitive passed to it (x
). The selection in line 13 uses the match
expression to identify the paints. More composite data types can be found in the collections package in Pony's standard library, in the form of set
and map
.
Reference Capabilities
Reference capabilities (Table 2), which Pony uses to prevent data races, are a special feature that programmers use to avoid setting multiple pointers to a variable object with two or more actors.
Table 2
Reference Capabilities
Type | Sendable | Write Permission | Read Permission |
---|---|---|---|
iso |
Yes* |
Exclusive |
Exclusive |
trn |
No |
Exclusive |
Shared |
ref |
No |
Shared |
Shared |
val |
Yes |
No |
Shared |
box |
No |
No |
Shared |
tag |
Yes |
No |
No |
*Yes, but only after deleting the sender. |
Using reference capabilities and dealing with the resulting effects can initially cause some difficulty; programmers will probably need a ramp-up period. The expression var picasso: Painter iso
, for example, would declare the reference picasso
, which points to an object of type Painter
. Thanks to the iso
capability, it receives exclusive write and read access for the object. Because picasso
is the only reference to the object, it can be sent safely to another actor after picasso
is deleted.
To write meaningful programs, Pony also needs the other capabilities from Table 2. Pony sends objects of the val
capability to all actors, much like a broadcast, because these objects are immutable (read but no write permissions). The trn
and box
types provide for data processing in the actor. The ref
capability acts as a standard for variables and behaves like a pointer in other programming languages; tag
actors protect against direct access.
Communication in the actor model relies on calling behaviors. The Rust language also limits pointers to avoids data races. Its user rights [8] only allow a reference with exclusive write and read access for each object. Developers grant the exclusive right to write useful programs.
Actors
Actors orchestrate the Pony application. Once started, they wait for asynchronous messages, evaluate the data supplied in accordance with the integrated behaviors, and send the results to other actors. Listing 5 shows the Painter
actor from the sample application that consumes paints and reports consumption to the Main
actor. An actor is similar to a class but also saves the behaviors referred to earlier.
Listing 5
painter.pony
The constructor of the Painter
actor accepts a reference from the Main
actor in line 5 (the one from Listing 6, line 6) and stores it in the listener
field. The history
field (Listing 5, line 3) keeps a record of all Resource
objects sent via paint
. Lines 8 to 15 define the paint
behavior. It also requires an object of type Resource
. If the level of the resource in line 9 is greater than zero, the history
field saves another reference when the push()
method in line 10 is called. Because the res
reference has exclusive rights (thanks to the iso
capability), push()
first uses consume res
to delete res
. The next line sends the output to the stats()
method of line 17 by sending the reference stored in listener
to the notify
behavior of actor Main
(Listing 6, line 12).
Listing 6
main.pony
Continuing with Listing 5, the stats()
method iterates in lines 19 to 25 over all paints from the primitives in Listing 4 in a loop defined by the return value of the list()
method from the same listing.
Internally, loops in Pony do not work directly with fields, but with their iterator objects. Listing 5 generates an object by appending it to .values()
(line 21). For each primitive, the run-time variable x
iterates across all received resources. Line 22 totals up the quantity of paint consumed using the level()
method from Listing 3. The summation uses an if
expression for filtering. For all non-matching primitives from the history, the else
branch adds
to the sum.
Another decision also needs to be made: If the paint resource res
in line 9 is empty, the program processes the else
branch from line 12. The res
variable has the iso
reference capability to comply with the required write and read rights from the fill()
method declaration, which is stated as ref
(Listing 3). The call in Listing 5, line 13, thus increments the private _amount
field by one. Then, paint
sends res
recursively to itself but deletes res
once again in line 14 with the help of consume
.
« Previous 1 2 3 Next »
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.