ETOOBUSY 🚀 minimal blogging for the impatient
Block syntax for Perl package definitions
TL;DR
Figuring out a feature that’s there since almost 12 years.
Often times I use iterators in Perl to encapsulate an iterative behaviour that might go on indefinitely, or that I’d like to consume one item at a time (as opposed to exausting the whole iteration at once). This is usually done with a closure, like this:
sub iterate_by2 ($n) {
$n -= 2;
return sub { return $n += 2 }
}
OK, OK, there’s a lot to be desired regarding corner cases but you get the idea.
I consistently found myself in a different state of mind while translating these things in Raku. I mean, they might be translated almost by the letter, but I always felt that a class was the way to go:
class IterateBy2 {
has $!n;
submethod TWEAK (:$n) { $!n = $n - 2 }
method get() { return $!n += 2 }
}
(I hope the code above works, I didn’t test it).
This is also what happened in previous post Portable(ish) Random(ish) Number Generator, which anyway left me with a bit of itch in the Perl implementation because I had three different behaviours scattered over three different functions:
- the
seed_to_num
function to turn a string into an integer - the actual iterator
randomish_uint32_it
- the iterator transformer to get random bits
get_bit
.
The underlying reason why I have this different approach, I think, lies in the lack of a native, dedicated syntax for declaring classed and from the fact that I started dabbling seriously when 5.8 was out, i.e. at a time where a lot of the new features were not around.
In time, I tended to avoid the features in the hope of preserving
compatibility with older versions, especially because often times I did
not know which perl
I would have found at some location. So I only
adopted the defined-or //
syntax (although not always) and, more
recently, the signatures by requiring that my stuff runs at least in
v5.24.
In this specific case, I was disregarding two facts:
-
package
definitions can be scoped to an enclosing BLOCK (something I figured out consciently only recently, with A block… blocks) -
since
perl
v5.14, released May 2011, we also have thepackage NAME { ... }
syntax in our toolbox.
And yet, it’s still somehow written in my mind that I have to change
package
all along, which is the exact barrier that often times
prevents me from using the object-oriented approach.
So, without further ado, it’s time to translate Randomish
from
Raku back to Perl, in true object-oriented glory:
package Randomish {
sub new ($package, $seed = undef) {
my $self = bless {}, $package;
say "pre<$seed>";
if (! defined($seed)) { $self->{s} = time() }
elsif ($seed =~ m{\A(?: 0 | [1-9]\d* )\z}mxs) { $self->{s} = $seed }
else {
my $val = 0;
$val = ($val << 8) | ord(substr($seed, $_))
for 0 .. length($seed) - 1;
$self->{s} = $val & 0xFFFFFFFF;
}
say "pos<$self->{s}>";
return $self;
}
sub uint32 ($self) {
$self->{s} = ($self->{s} * 1664525 + 1013904223) & 0xFFFFFFFF;
}
sub bit ($self) { $self->uint32 & 0x80000000 ? 1 : 0 }
}
Bad habits are hard to remove because they’re hard to spot.
Stay safe!