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
-
Linux Servers Targeted by Akira Ransomware
A group of bad actors who have already extorted $42 million have their sights set on the Linux platform.
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
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