Skip to content

Instantly share code, notes, and snippets.

@duffee
Last active December 7, 2018 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duffee/9947a49b3448d2febe69a874df7af4a2 to your computer and use it in GitHub Desktop.
Save duffee/9947a49b3448d2febe69a874df7af4a2 to your computer and use it in GitHub Desktop.
Perl 6 advent post - Constants

Let's get astroPhysical! - Constants in Perl 6

I wrote my first Perl 6 program (that is, one that worked) the day before the London Perl Workshop where I proudly told people. So, JJ says "Why don't you write an Advent calendar post for Perl 6?"

With only one program under my belt, what do I have to write about? Well ... I authored Astro::Constants in Perl 5, so how hard would it be to migrate it to Perl 6?

Since I couldn't keep my big gob shut, I give you the tale of a Perl 5 module author wandering through the Perl 6 landscape.


If on Day 5 you were "diagnosed" as a Constant, you need today's post.

We're used to using variables for counting things and holding stuff. Totals change as we get more "stuff". Constants are those values that should never change. Things like the number of seconds in a day or the speed of light. Sure, we use them like variables in our calculations, but you don't want to accidentally change a constant through assignment such as

$SPEED_LIGHT = 30;

or even accidentally when you meant to test if it was equal to some value, like this

if ( $SECONDS_IN_A_DAY = $seconds_waited) {

when you really meant

if ( $SECONDS_IN_A_DAY == $seconds_waited) {

In these cases, you want the compiler to say "I'm sorry, Dave. I'm afraid I can't do that." The Perl compiler comes close. If you try the first line, you'll get

Cannot modify an immutable Num (299792458)
  in block <unit> at im_sorry_dave.p6 line 12

Click here for the full explanation

How to make a Constant

To make a variable constant, you declare it with the constant keyword.

constant $tau = pi * 2;

and Hey! the sigil is optional, so I can use my favourite style for constant declarations

my constant SPEED_LIGHT is export = 2.99792458e8;

And all this fun is not just for scalars. Lists and hashes can be declared constant, too!

Why would you want to make a List constant? How about for the months of the year, which prevents this

my constant @months = <Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec>;
...
@months[9] = 'Hacktober';   # changing a name
push @months, 'Hogmannay';  # we'd all like more time after Christmas

if you try either of these, you get

Cannot modify and immutable Str (D)     # error for the assignment
# or
Cannot call 'push' on an immutable 'List' # error for the push

As an aside, tau, pi, e and i are all built-in constants in Perl 6, along with their Unicode equivalents, τ, π and 𝑒. Also seems that you can get the same behaviour with sigil-less variables but let's not go there today.

Exporting Constants from a Module

If you're going to be using the same constants over and over in your code, it makes sense to put them in a module (a separate file) and load that into your programs. Now I have to admit a touch of cargo-cult programming here, but this is what worked for me and I'll try and explain it to the best of my initiate's ability.

use v6;
unit class Astro::Constants:ver<0.0.1>:auth<github:DUFFEE>;

my constant SPEED_LIGHT is export = 2.99792458e8;
...

Line 1 - easy start. use v6; tells the compiler that this is a Perl 6 program. Wait! I don't need that there. It's just a hold-over from writing the programs. I can get rid of it.

Line 2

  • unit means that this file provides only one module - no idea what that implies
  • class creates the lexical scope of the file - but I probably could have used module instead which is for code which doesn't belong inside a class. Hmmm, guess I'll have to think about my code design a bit deeper. But it still worked!
  • Astro::Constants - module name
  • ver<0.0.1> - the version string, now up in the package declaration.
  • auth<github:DUFFEE> - well, this is the author. It's a little freaky to be adding higher dimensions to package names, but it does let you specify who's version of a module to use. No more issues with name-space camping in PAUSE.

Line N my for the lexical scope; constant to make it read-only; SPEED_LIGHT is the name of the constant; is export allows the constant to be used outside the module, i.e. in your code; and 2.99792458e8 is just the Perl way of expressing 2.99 × 10⁸.

... and for completeness, how about finishing the module with a version method and some documentation

method ver { v0.0.1 }

=begin pod

=head1 DESCRIPTION

A set of constants used in Physics, Chemistry and Math

=end pod

A side effect of putting your constants into a module is that they are computed at compile time It should make your code run faster, but the compiled module persists. This is great for constants, but if your module contains something that you might want to change, it will need to be re-compiled.

Using Modules in your Programs

Once you have a module, how do you use it in a program?

In this example, I created a directory mylib/Astro and put the module in a file called mylib/Astro/Constants.pm6. This is my program

use v6;
use lib <mylib>;
use Astro::Constants;

say "speed of light =\t", SPEED_LIGHT;

and it worked! To explain the first 3 lines: use v6 says to use Perl 6; use lib <mylib> says to add the path <mylib> to the library search path; and use Astro::Constants says to search the library path for a file Astro/Constants.pm6 and load it.

Do I have to do all this? ... No.

Why re-invent the wheel? The aforementioned JJ has previous form with constants, but you'll want a package manager to do the work of installing it. In Fedora 28, use dnf install rakudo-zef to install the package manager, zef. Then you can search for any modules that deal with constants. Running

zef search Constants

will give you at least 15 packages registered in the ecosystem, not all of them are what you're looking for. You could get started right away with zef install Math::Constants and use JJ's module or you could use the search to see if I've found the time to upload my attempt (probably named Physics::Constants by then), coming in 2019 with all the summer blockbusters.

Finally, a few comments on code maintainance

For me, code maintainance is the most importance consideration in scientific programming. Think of the new science student who walks in the door of $graduate-school and gets handed your code to maintain on Day 1. Guaranteed by Day 20, they've been asked to make a change. For their sake, I like to write for clarity rather than brevity because there are so many overloaded symbols in science. Because of this, I'm wary about throwing symbols into my calculations. Maybe I'm worrying for nothing, but the only way to find out is to do it and see if it hurts.

One possibility that's occurring to me right now is to be able to specify what constants you are referring to. This made up example looks a little like Python. Might be worth stealing.

import GRAVITATIONAL as G;
...
$F_between_two_bodies = G * $mass1 * $mass2 / $distance**2;

I'll be reading Perl 6 Deep Dive over Christmas and I'll let you know how I got on next year.

Happy Science-ing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment