I was looking at my normal youtube feed when Leon Timmermans came up with a presentation about Raku. (Certainly interesting, and I have questions for him, but not now.) I soon realized that the zoom convention was happening, and that I could get it in essentially real time on youtube. I have them on as I go about my business, and B Estrade's talk comes on. I went about cleaning the kitchen at the start, but once it started into graph theory, I got very interested, and gave it my full attention. As things started cooking, the moderator chimed in that five minutes remained, and the presenter was left to rush through slides, to my, and seemingly, his dismay. He didn't get to running code, but I was interested enough to see what I could dig up. I feel like there was a second half to the talk that I would gladly hear. I tried to fill in the gaps by working some code, and I would like to post sources, output and questions.
I'll present with a script that came from Sub-Genius, with the exception of one line changed. It is the first of his japh examples. If you download this precise script, then the breakpoints I give here will make sense. I didn't move any working code up or down. Here is 1.japh.pl:
#!/usr/bin/env perl
use v5.30.0; # implies strict
use warnings;
use feature 'state';
use FindBin qw/$Bin/;
use lib qq{$Bin/../lib};
use Sub::Genius ();
#
# Implements classic JAPH, perl hacker hackerman benchmark
# sequentially consistent, yet oblivious, way - that's right!
# This is a Sequential Consistency Oblivious Algorithm (in the
# same vein as 'cache oblivious' algorithms
#
# paradigm below is effective 'fork'/'join'
#
my $pre = q{
begin
(
J &
A &
P &
H
)
end
};
# Load PRE describing concurrent semantics
my $sq = Sub::Genius->new(preplan => $pre );
my $GLOBAL = {};
# 'compile' PRE
$sq->init_plan;
# run loop-ish
$sq->run_once(
verbose => $ARGV[0],
# 'scope' is passed as reference to all calls, effectively
# acts as shared memory, federated only among subroutine
# participating in the serialized excecution plan
scope => {
japh => [ qw/just Another perl/, q{Hacker,} ],
curr => 0,
contrib => [],
}
);
# Dump $GLOBAL that's now been changed
if ( $ARGV[0] ) {
print qq{\n... actual contributions of each sub ...\n};
foreach my $k ( keys %$GLOBAL ) {
printf( qq{ %s() => %s\n}, $k, $GLOBAL->{$k} );
}
}
# #
## S T A T E S U B S ##
# #
# noop
sub begin {
my $scope = shift;
state $persist = {}; # gives subroutine memory, also 'private'
my $private = {}; # reset after each call
return;
}
sub J {
my $scope = shift;
state $persist = { akctual => $scope->{japh}->[ $scope->{curr} ],
+}; # gives subroutine memory, also 'private'
+ # sub's killroy
$GLOBAL->{J} = $persist->{akctual};
++$scope->{curr};
my $private = {};
+ # reset after each call
push @{ $scope->{contrib} }, $persist->{akctual};
return;
}
sub A {
my $scope = shift;
state $persist = { akctual => $scope->{japh}->[ $scope->{curr} ],
+}; # gives subroutine memory, also 'private'
+ # sub's killroy
$GLOBAL->{A} = $persist->{akctual};
++$scope->{curr};
my $private = {};
+ # reset after each call
push @{ $scope->{contrib} }, $persist->{akctual};
return;
}
sub H {
my $scope = shift;
state $persist = { akctual => $scope->{japh}->[ $scope->{curr} ],
+}; # gives subroutine memory, also 'private'
+ # sub's killroy
$GLOBAL->{H} = $persist->{akctual};
++$scope->{curr};
my $private = {};
+ # reset after each call
push @{ $scope->{contrib} }, $persist->{akctual};
return;
}
sub P {
my $scope = shift;
state $persist = { akctual => $scope->{japh}->[ $scope->{curr} ],
+}; # gives subroutine memory, also 'private'
+ # sub's killroy
$GLOBAL->{P} = $persist->{akctual};
++$scope->{curr};
my $private = {};
+ # reset after each call
push @{ $scope->{contrib} }, $persist->{akctual};
return;
}
sub end {
my $scope = shift;
state $persist = {};
+ # gives subroutine memory, also 'private'
my $private = {};
+ # reset after each call
printf( "%s\n", join( q{ }, @{ $scope->{contrib} } ) );
return;
}
exit;
The only difference is the change from
use strict;
to
use v5.30.0; # implies strict
Normally, I would get my strictness by using the version number alone, thus:
use 5.30.0;
Q1.a) Are the above statements semantically equivalent in perl5?
Q1.b) Will they be in perl 7?
There was *a lot* said about use v in Suckitude 2020, and there seems to be many and varying opinions. I don't know where the whole thing ended up. Q1.c) Let me ask this, if I am going to use a version number, is this now preferred syntax?
use v5.30.0; # implies strict
For output I have the source files from runs with the debugger. I need to play with software to understand it. The following source worked for getting a look at this script using the debugger. I built my way to this with runs and edits:
b 70
b 82
b 94
b 106
b 118
b 126
c
c
v
p $persist->{akctual}
v
c
p $persist->{akctual}
v
c
p $persist->{akctual}
v
c
p $persist->{akctual}
v
c
p @{$scope->{contrib}}
#save 4.seq.txt
This yields:
$ perl -d 1.japh.pl jehosophat
Loading DB routines from perl5db.pl version 1.55
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(1.japh.pl:20): my $pre = q{
main::(1.japh.pl:21): begin
main::(1.japh.pl:22): (
main::(1.japh.pl:23): J &
main::(1.japh.pl:24): A &
main::(1.japh.pl:25): P &
main::(1.japh.pl:26): H
main::(1.japh.pl:27): )
main::(1.japh.pl:28): end
DB<1> source 4.seq.txt
+
>> b 70
>> b 82
>> b 94
>> b 106
>> b 118
>> b 126
>> c
plan: "begin A H J P end" <<<
Execute:
main::begin(1.japh.pl:70): return;
>> c
main::A(1.japh.pl:94): return;
>> v
91: ++$scope->{curr};
92: my $private = {};
+ # reset after each call
93: push @{ $scope->{contrib} }, $persist->{akctual};
94==>b return;
95 }
96
97 sub H {
98: my $scope = shift;
99: state $persist = { akctual => $scope->{japh}->[ $scope->{cu
+rr} ], }; # gives subroutine memory, also 'private'
100
+ # sub's killroy
>> p $persist->{akctual}
just
>> v
98: my $scope = shift;
99: state $persist = { akctual => $scope->{japh}->[ $scope->{cu
+rr} ], }; # gives subroutine memory, also 'private'
100
+ # sub's killroy
101: $GLOBAL->{H} = $persist->{akctual};
102
103: ++$scope->{curr};
104: my $private = {};
+ # reset after each call
105: push @{ $scope->{contrib} }, $persist->{akctual};
106:b return;
107 }
>> c
main::H(1.japh.pl:106): return;
>> p $persist->{akctual}
Another
>> v
103: ++$scope->{curr};
104: my $private = {};
+ # reset after each call
105: push @{ $scope->{contrib} }, $persist->{akctual};
106==>b return;
107 }
108
109 sub P {
110: my $scope = shift;
111: state $persist = { akctual => $scope->{japh}->[ $scope->{c
+urr} ], }; # gives subroutine memory, also 'private'
112
+ # sub's killroy
>> c
main::J(1.japh.pl:82): return;
>> p $persist->{akctual}
perl
>> v
79: ++$scope->{curr};
80: my $private = {};
+ # reset after each call
81: push @{ $scope->{contrib} }, $persist->{akctual};
82==>b return;
83 }
84
85 sub A {
86: my $scope = shift;
87: state $persist = { akctual => $scope->{japh}->[ $scope->{cu
+rr} ], }; # gives subroutine memory, also 'private'
88
+ # sub's killroy
>> c
main::P(1.japh.pl:118): return;
>> p $persist->{akctual}
Hacker,
>> v
115: ++$scope->{curr};
116: my $private = {};
+ # reset after each call
117: push @{ $scope->{contrib} }, $persist->{akctual};
118==>b return;
119 }
120
121 sub end {
122: my $scope = shift;
123: state $persist = {};
+ # gives subroutine memory, also 'private'
124: my $private = {};
+ # reset after each call
>> c
just Another perl Hacker,
main::end(1.japh.pl:126): return;
>> p @{$scope->{contrib}}
justAnotherperlHacker,
>> #save 4.seq.txt
DB<14> q
+
$
I'm still not quite sure what all I'm looking at here, but I continue with the debugger to pick at it. Here is another source file that I found illuminating:
M
b 82
c
y
c
#save 3.2.txt
$ perl -d 1.japh.pl jesophat
...
DB<1> source 3.2.txt
+
1.japh.pl* 2.seq.txt 3.2.txt 4.seq.txt _Sub::
+Genius/
1.seq.txt 3.1.txt 3.seq.txt 5.seq.txt
DB<1> source 3.2.txt
>> M
'FLAT.pm' => '1.0.4 from /usr/local/share/perl/5.30.0/FLAT.pm'
'FLAT/DFA.pm' => '/usr/local/share/perl/5.30.0/FLAT/DFA.pm'
'FLAT/DFA/Minimal.pm' => '/usr/local/share/perl/5.30.0/FLAT/DFA/Minima
+l.pm'
'FLAT/FA.pm' => '/usr/local/share/perl/5.30.0/FLAT/FA.pm'
'FLAT/NFA.pm' => '/usr/local/share/perl/5.30.0/FLAT/NFA.pm'
'FLAT/PFA.pm' => '/usr/local/share/perl/5.30.0/FLAT/PFA.pm'
'FLAT/Regex.pm' => '/usr/local/share/perl/5.30.0/FLAT/Regex.pm'
'FLAT/Regex/Op.pm' => '/usr/local/share/perl/5.30.0/FLAT/Regex/Op.pm'
'FLAT/Regex/Parser.pm' => '/usr/local/share/perl/5.30.0/FLAT/Regex/Par
+ser.pm'
'FLAT/Regex/WithExtraOps.pm' => '/usr/local/share/perl/5.30.0/FLAT/Reg
+ex/WithExtraOps.pm'
'FLAT/Symbol.pm' => '/usr/local/share/perl/5.30.0/FLAT/Symbol.pm'
'FLAT/Symbol/Regex.pm' => '/usr/local/share/perl/5.30.0/FLAT/Symbol/Re
+gex.pm'
'FLAT/Transition.pm' => '/usr/local/share/perl/5.30.0/FLAT/Transition.
+pm'
'FLAT/Transition/Simple.pm' => '/usr/local/share/perl/5.30.0/FLAT/Tran
+sition/Simple.pm'
>> b 82
>> c
plan: "begin A P J H end" <<<
Execute:
main::J(1.japh.pl:82): return;
>> y
$GLOBAL = HASH(0x557b5132e420)
'A' => 'just'
'J' => 'perl'
'P' => 'Another'
$persist = HASH(0x557b5251d3b8)
'akctual' => 'perl'
$private = HASH(0x557b5251d298)
empty hash
$scope = HASH(0x557b524e0fd8)
'contrib' => ARRAY(0x557b5132e3d8)
0 'just'
1 'Another'
2 'perl'
'curr' => 3
'japh' => ARRAY(0x557b510bec80)
0 'just'
1 'Another'
2 'perl'
3 'Hacker,'
$sq = Sub::Genius=HASH(0x557b5214ad38)
'DFA' => FLAT::DFA=HASH(0x557b524d2410)
'ALPHA' => HASH(0x557b524e1a28)
'A' => 8
'H' => 8
'J' => 8
'P' => 8
'begin' => 1
'end' => 1
'preplan' => '[begin]([J]&[A]&[P]&[H])[end]'
'preprocess' => 1
>> c
just Another perl Hacker,
... actual contributions of each sub ...
H() => Hacker,
P() => Another
A() => just
J() => perl
Debugged program terminated. Use q to quit or R to restart,
It helps for me to see the notation at different stages. Also, I can quickly get to the documentation in the sources, which was excellent. You don't know what FLAT is until you do:
$ perldoc /usr/local/share/perl/5.30.0/Sub/Genius.pm
$ perldoc /usr/local/share/perl/5.30.0/FLAT.pm
$ perldoc /usr/local/share/perl/5.30.0/FLAT/DFA.pm
Other things I tried to grapple with, but struggled with notation, like Thompson%27s_construction. I did stumble on this, and it seems to address a lot of this history: 2007 article on regex performance. Perl compares unfavorably, and it was refuted in
Re: Perl regexp matching is slow??. grinder gives an example that avoids greedy matching.
Q2.a) Is it best to avoid greedy matching unless you need it?
Q2.b) Would any of the 'no' pragmata close this performance loophole?
I thought the joke that perl was "an OS in need of a better programming language" was funny. I have one final question about the thing that keeps me in perl right now, the debugger:
Q3) Is there a term for the files one saves from debugging sessions, that is the files that are accessed using the source command?
Thanks to presenters. I've seen several and might need half a year to see them all. I appreciate your service. Thanks also for comments,