Saturday 18 June 2022

Make the Raku programming language familiar to C++ programmers

So a couple of days ago I was taken with the fact that you could make the Raku programming language appear to do I/O somewhat like C++:

Now it occurs to me that this may be somewhat opaque to someone not familiar with Raku, so, rather than explain it in a bunch of tweets, I'll give a quick breakdown here

First up the weird looking "use isms;":  Raku has some heritage from languages that have some different operators for common operations such as "left shift", and to help avoid common mistakes due to these differences, rakudo goes out of its way to provide a helpful error message when the programmer uses one of the common operators that have different meanings or none at all in Raku,  So for example if one was to use the "left shift" (or C++ stream extraction in this case,) operator one would get something like:

[jonathan@menenius hesabu]$ raku -e 'my $a = 1; say $a << 2'
===SORRY!=== Error while compiling -e

Unsupported use of << to do left shift.  In Raku please use: +< or ~<.

at -e:1

------> my $a = 1; say $a <<⏏ 2

The "use isms;pragma turns off this behaviour, so you get a different error message,  helpful in a different way, but assuming you know what you are doing:

[jonathan@menenius hesabu]$ raku -e 'use isms; my $a = 1; say $a << 2'

===SORRY!=== Error while compiling -e

Variable '&infix:«<<»' is not declared.  Perhaps you forgot a 'sub' if

this was intended to be part of a signature?

at -e:1

------> use isms; my $a = 1; say $a ⏏<< 2

Which kind of gives us a clue to what we need to do to implement something like the C++ stream extraction operator.

Raku allows you to define new operators (or define new candidates for some existing operators with different meanings for different "arguments",) by defining a new subroutine that specifies the operator's behaviour for the specific arguments.  In the case of the "<<"  we want to define an infix operator (that is one that has two "arguments" to the left and right of the operator,) so one define something like the C++ stream extraction operator something like:

sub infix:«<<» ( IO::Handle $h, Cool $v ) { $h.print: $v; $h }

That is to say a subroutine that will be called when the operator "<<"  is used with an IO::Handle (which is the base class of most IO classes,) on the left hand side and a Cool (which is the base class for most of the built in Scalar types such as Str, Int etc,) on the right hand side. It returns the LHS handle so an expression using this operator can in turn be used on the LHS of further uses of the operator and so on.

So this allows us to do:

$*OUT << "foo";

(omitting the actual definition of the operator and the "use isms;" that allows it to work.)

The "$*OUT"  is a "Dynamic Variable", that is one that can be redefined by assignment within a runtime scope (retaining the original value in outer scopes,) by default it is the IO::Handle for STDOUT.

But in C++ the stream object is "cout"  so to be more like C++ we need to use that bareword  symbol rather than Raku's dynamic variable to represent the target handle.

Now we could express that as a regular subroutine, or as a sigil-less constant but the former has constraints on where it can be used without (even empty,) argument list, and the latter won't retain the dynamic behaviour of the underlying value (being set at compile time.)  So this will be defined as a "term".

A "term" is defined as a subroutine without any arguments that can be used anywhere that a value can be used in Raku code (builtin examples include now and pi,) so we can define "cout" simply as

sub term:<cout> { $*OUT }

Which allows cout to be used anywhere that a value can be used without needing parentheses and will still allow the underlying value to be set within the runtime scope.

Obviously then the C++ symbol "endl" can be defined simply as:

sub term:<endl> { "\n" }

And there you have it:

use isms; 

sub infix:«<<»( IO::Handle $h, Cool $v ) { $h.print: $v; $h }; 

sub term:<cout> { $*OUT }; 

sub term:<endl> { "\n" }; 

cout  << "Whatever" << endl;

Making the Raku programming language more familiar to C++ programmers. 

Saturday 5 February 2022

Making a home thermostat with a Raspberry Pi and the Raku Programming Language. Part 1: getting the temperature.

A few weeks ago I had a moment of hubris on Twitter

I was particularly interested in the idea of making a thermostat with a Raspberry Pi but using Raku instead of Python. Being somewhat impatient and impulsive I bought all the parts I thought I would need from Amazon and set about thinking about what the software would need to do.

The digital thermometer used (the DS18B20 from Maxim Integrated,) seemed to be the natural place to start so I wrote a Raku module to read the temperatures from one or more of the devices. As this may be more generally useful in another programme and I can leave you with a somewhat useful programme without all the other parts, we'll start with this part.

The DS18B20 is a digital thermometer that uses the Dallas 1-Wire interface, the nature of the interface means that a number of the devices can be attached using only a single GPIO pin on the Raspberry Pi. The 1-Wire protocol in general and thermometers specifically are fairly well supported by the Raspberry Pi OS, presenting each attached device as nodes in the sysfs

Assuming you have the RPi::Device::DS18B20 installed on your Raspberry Pi you will only need one or more DS18B20 devices (I'm using the encapsulated "waterproof" ones with longer wires, it seems it's just as cheap to buy five of these from Amazon than the bare chips,) a 4.7K resistor and for convenience a solderless breadboard and some patch cables.

The circuit itself is really quite simple:

Additional thermometers can be added by providing the power and linking the data lines (the yellow wire.)

With this circuit you can run the synopsis example:

And you should get some output like:

28-012113620c31:	20.562
28-03213194ea4f:	17.25

I have two thermometers attached. The first thing you've probably noticed is the "name" of the devices, this device ID is basically baked in the chip at manufacture and not very human friendly so we'll providing a mapping of these to more useful names as we build the application.

For the first part of this we'll create a web application with Cro::HTTP which displays the temperatures dynamically, and for this kind of purpose RPi::Device::DS18B20 provides an asynchronous interface via a which provides the readings periodically:

This emits a Reading object for each attached device periodically, because the thermometers may take different times to produce a result they may not be in any particular order but this means that, unlike the first example, you don't have to wait for a preceding reading which is taking longer. This is ideal for a web application where we can use Server Sent Events with EventSource::Server and some javascript on the client side to update the web page when new reading become available.

Given that we already have a Supply from the RPi::Device::DS18B20 and the EventSource::Server can take a Supply of the events to be emitted we can do the majority of the work by mapping one Supply to one suitable to pass to the EventSource::Server:

Here we are mapping the Reading objects emitted by the RPi::Device::DS18B20 Supply to a custom class TemperatureEvent which contains the mapped name of the device, the device id and the temperature. This class does the role JSON::Class so the objects can be trivially serialised to JSON in the next step where the JSON representation of the object is mapped into a EventSource::Server::Event with a type of 'reading'.

Here I've used a plain Hash to lookup the user friendly name from the device id,for a larger programme it may be more suitable in some configuration or other storage. If you do have more than thermometer device the easiest way to derive the lookup is to apply some source of warmth to each device in turn (a hot liquid or even holding it in your hand,) while running the first example each time, noting the device id with the raised temperature (and possibly labelling for future reference.)

And that is basically that, all that remains is to provide the out-supply of the EventSource::Server object as the content of an appropriate route in the Cro::HTTP application and provide a web-page in which to display the readings and we're done:

The index.html is simply:

Which basically arranges to read the events from the stream and update the table as appropriate. It could obviously be a bit prettier but we'll leave that for later.

In the next post or posts we'll update this application to do the other part of the thermostat application which is to turn relays on and off in order to control the central heating, but as I'm taking a slightly different approach than the post that inspired this I'll need to write a library to drive an MCP23017 first.

The code of the example can be found on Github

Thursday 15 October 2015

Learning Perl 6 from bad Perl 5 code

My friend Dave Cross doesn't like to see bad Perl code in the wild, and often when he finds it he will write about it,usually presenting a rewritten version that conforms to the generally accepted standards for writing Perl 5 code in the 21st century.

Anyway yesterday I saw this magazine in a supermarket:

It has three good articles by Dave in it, and, as Dave pointed out on Facebook, the article he wrote about in Learning from Bad Code (if you haven't already read that you may want to do it now as it'll save me copying the code and re-iterating what Dave said about it.)

So it occurred to me that this bad code would provide a good didactic vehicle for introducing Perl 6, especially as Dave had already provided a good quality Perl 5 example with which it can be compared.

So I wrote a Perl 6 version of the Starfield example:

This is approximately the same length as Dave's (I've been concise in some places and verbose in others, it could probably be done in fewer lines if one was so inclined.) I've used the Perl 6 module NCurses which is basically the same as the Perl 5 module in the example except it doesn't provide an object oriented interface.

If you're already familiar with Perl 6 you'll probably already understand the code.

The first thing you may notice is that there is no "use strict" or "use warnings" in the code, this is because that these things are effectively on by default, which means (among other things,) that variables must be declared and types defined before they are used.  Perl 6 in general will catch a lot more problems with code at compile time, (and typically provide more helpful error messages,) which can significantly enhance the programmer's experience.

The "use v6" is not strictly necessary here, (infact it is basically ignored by the Perl 6 compiler,) however it is of benefit when you are working in both Perl 6 and Perl 5 as it will give rise to an error such as
Perl v6.0.0 required--this is only v5.20.3
When run as Perl 5 code, rather than something more confusing when it fails to parse the Perl 6 code later on.

Rather than use variables for the basic parameters of the program in my example I have used constants defined with the "constant" keyword, this is conceptually similar to "use constant" in Perl 5 in that it introduces a name that can be used in place of some value later in the code, however, unlike "use constant" which creates a constant subroutine which limits it's use in certain places in your code, it introduces a "term" which can be used anywhere that, for example, a literal value can be used.

The names of the constants warrant mention too:  Perl 6 allows the use of a hyphen in identifiers (such as variable or subroutine name, or constants as here,) there is a definite preference toward "Kebab Case" as opposed to "Snake Case", as typically found in Perl 5.  In some places this may lead to a reduction in brevity (because more white space becomes significant,) but this reflects a general inclination in favour of clarity and consistency over brevity in the design.

I've used objects of the class "Star" to hold the star data and provide the movement behaviour. Dave's choice to use a hash to store the star data is sensible in a short program like this: in Perl 5 you would either have to provide an amount of boilerplate code to define the constructor and the accessors or use a fairly heavyweight external module such as Moose; with Perl 6 you get a powerful and clean object system out of the box: this is all documented in the Object Orientation document, so I'll just describe the things that I have implemented.

The BUILD submethod here isn't strictly necessary as the values could have been supplied as default initializers to the attributes directly, but it makes things clearer in this example.  The initialising expressions are quite a common idiom:  using ".pick" on a list defined by an appropriate Range; Range is similar to the '...' range operator in Perl 5 but somewhat more generalised and more powerful, they crop up regularly in loop constructs, array slices and so forth.

The observant may have noticed that the attributes of the class are declared as $.x, $.y and $.s but are used as $!x, $!y and $!s in the BUILD.  This is quite common within classes: the '.' "twigil" declares the attribute as being public and a public accessor will be created for it, within the methods of the class itself the attribute can be referred to directly with the '!' twigil without going through the public accessor,  by default the public accessor is read-only so within the class it can only be assigned to this way.  The accessor can be made writeable by applying the "is rw" trait to the definition but this isn't necessary here.

The "move"  method uses the "ternary" or "conditional" statement for brevity as opposed to the two separate statements in the original example, this works exactly the same as it does in Perl 5, just the '?' and ':' of Perl 5 have been renamed to '??' and '!!' for reasons of grammatical simplicity.

The array of star objects is declared and initialised in a single statement for brevity: the array is declared as being comprised of Star objects, any attempt to add anything else to it will result in a fatal error, this can reduce complexity and aid debugging in larger programs but isn't really necessary here and could be omitted. Of course arrays without a declared type can hold any types of objects just as in Perl 5.

In order to keep the initialiser to one line and still be readable I have used "gather"/"take": the gather basically returns an iterator with one item for each time a "take" is encountered; the "for" statement modifier here works pretty much the same way as in Perl 5:  the "take" is executed 'numstars' times (i.e 100 times.) The gather's iterator is automatically expanded on assignment to the array.

While Perl 6 does still support the "while(1)" in the Perl 5 (though it would probably be better written "while(True)" as Perl 6 has true booleans,) it is more idiomatic to use "loop" for an infinite loop of this sort.  The "loop" statement replaces the three-part or "C-Style" "for" in Perl 5 and its bare usage here is equivalent to "loop (;;)"; the "for" in Perl 6 no longer supports this iterator style.

The inner loop iterating over the array of Star objects illustrates the way the "for" loop statement differs from that in Perl 5 (incidentally the "foreach" synonym no longer exists, Perl 6 code only has "for".) At its simplest the Perl 6 "for" can be thought of as iterating over the supplied list and for each item executing the associated block with the item as an argument; by default the item is passed in the 'topic' variable "$_"  much as in Perl 5, however, as in this example, the argument can be named with the argument variable ( or variables separated by a comma,) following the '->'; in the Perl 6 jargon this is known as a "pointy block" and can be thought of as an anonymous subroutine with the specified parameters.  the parameter variable doesn't need to be declared with 'my' as you might the target variable in Perl 5 as the declaration is implicit in it being a parameter.

So there you have it, the Perl 6 version is not much longer than the good Perl 5 one and is at least as readable and maintainable  It uses the Perl 6 Object Orientation features without adding unwanted cruft to the code so you could extend the behaviour of the stars without changing the body of the code.

Perl 6 not as frightening as you thought it was.