Perl in 2025
Paul “LeoNerd” Evans (PEVANS)
Perl in 2025 2030
Paul “LeoNerd” Evans (PEVANS)
Perl in 2025
2020 Perl Advent Calendar
Turned into a presentation "Perl in 2025"
Completed
try/catch copied from Syntax::Keyword::Try
Subroutine signatures are now stable
use v5.40;��try {� some_func();�}�catch ( $e ) {� warn "It failed - $e\n";�}
use v5.36;��sub add ( $x, $y ) {� return $x + $y;�}
In Progress
class/field/method copied from Object::Pad
use v5.40;�use feature 'class';
class Point {
field $x :param :reader = 0;
field $y :param :reader = 0;
method describe () {
say "A point at ($x, $y)";
}
}
Perl in 2025
On CPAN right now
CPAN Experiments
Many modules in the Syntax::Keyword::* space
Provides new syntax in the form of leading keywords with custom parsing
CPAN Experiments�Syntax::Keyword::Match
Dispatch similar to given/when but with explicit comparison operator
use v5.18;
use Syntax::Keyword::Match;
match($var : eq) {
case("abc") { ... }
case("def") { ... }
case("1.0") { ... }
otherwise { ... }
}
if ($var eq "abc") { ... }
elsif($var eq "def") { ... }
elsif($var eq "1.0") { ... }
else { ... }
CPAN Experiments�Syntax::Keyword::Match
Dispatch similar to given/when but with explicit comparison operator
use v5.18;
use Syntax::Keyword::Match;
match(some_func() : eq) {
case("abc") { ... }
case("def") { ... }
case("1.0") { ... }
otherwise { ... }
}
if (some_func() eq "abc") { ... }
elsif(some_func() eq "def") { ... }
elsif(some_func() eq "1.0") { ... }
else { ... }
CPAN Experiments�List::Keywords
Same syntax as List::Util functionals, just more efficient
use v5.14;
use List::Keywords 'any';
my @boxes = ...;
if( any { $_->size > 100 } @boxes ) {
say "There are some large boxes here";
}
Syntax::Keyword::Any ?
CPAN Experiments�Future::AsyncAwait
Convenient syntax for asynchronous code/data flow using futures
use v5.22;
use Future::AsyncAwait;
async sub get_pages ( $base, $count ) {
my @pages;
foreach my $i ( 1 .. $count ) {� push @pages, await get_page "$base/$i";� }
return @pages;�}
Syntax::Keyword::Async ?
use v5.22;
use Future::AsyncAwait;
async sub get_pages ( $base, $count ) {
my @pages;
foreach my $i ( 1 .. $count ) {� push @pages, await get_page "$base/$i";� }
return @pages;�}
CPAN Experiments
Modules in the newer Syntax::Operator::* space
Provide infix operators rather than prefix syntax keywords
CPAN Experiments�Syntax::Operator::Equ
Equality comparisons that are aware of undef
use v5.38;
use Syntax::Operator::Equ;
my $str = ...;
if ( $str equ undef ) { say "Is undef"; }
elsif( $str equ "" ) { say "Is empty"; }
else { say "Is non-empty"; }
use Syntax::Operator::Equ;
"abc" equ "abc"; # true
"abc" equ "def"; # false
undef equ undef; # true
undef equ ""; # false
CPAN Experiments�Syntax::Operator::In
Test if an element is a member of a list
use v5.38;�use Syntax::Operator::In;��if( $n in:== (2, 3, 4) ) { say "Few items"; }
use v5.38;�use Syntax::Operator::Elem;��if( $n ∈ (2, 3, 4) ) {� say "Few items";�}
use v5.38;�use Syntax::Operator::Elem;��if( $colour elem qw( red orange yellow ) ) {� say "We like this colour";�}
in:==
in:eq
CPAN Experiments�Syntax::Operator::Zip
Infix operators to compose lists
use v5.38;�use Syntax::Operator::Zip;
foreach ( @epsilons Z @deltas ) {
my ( $e, $d ) = @$_;
...
}
use v5.38;�use Syntax::Operator::Zip;
foreach my ( $e, $d ) ( @epsilons M @deltas ) {
...
}
my %hash = @keys M @values;
CPAN Experiments�Sublike::Extended
Additional syntax for subroutine declarations
use v5.36;
use Sublike::Extended 0.29 'sub';
sub ping ( $target, :$count )�{
...
}
ping( "foo", count => 5 );
PPC 0024
CPAN Experiments�Sublike::Extended
Additional syntax for subroutine declarations
use v5.36;
use Sublike::Extended 0.29 'sub';
use Signature::Attribute::Alias;
sub trim ( $s :Alias )�{
$s =~ s/^\s+//;
$s =~ s/\s+$//;
}
my $str = " hello, world! ";
trim( $str );
say "<$str>";
<hello, world!>
CPAN Experiments�:Checked attribute
Apply value constraint assertions to subroutine parameters
use v5.36;
use Sublike::Extended 0.29 'sub';
use Signature::Attribute::Checked;
use Data::Checks qw( Num );
sub ping ( $target, :$count :Checked(Num) )�{
...
}
Named parameter :$count requires a value satisfying Num at -e line 1.
ping( "bar", count => "five" );
CPAN Experiments�:Checked attribute
Apply value constraint assertions to object fields
use v5.26;
use Object::Pad;
use Object::Pad::FieldAttr::Checked;
use Data::Checks qw( Num );
class Point {
field $x :Checked(Num) :param;
field $y :Checked(Num) :param;
...
}
Field $y requires a value satisfying Num at -e line 1.
Point->new( x => 10, y => "twenty" );
CPAN Experiments�Data::Checks
A collection of value constraint assertions
use v5.26;
use Data::Checks qw( Num );
if( Num()->check( $ARGV[0] ) ) {� say "OK";�}
else {� say "Bad";�}
$ perl check.pl 123
OK
$ perl check.pl hello
Bad
use v5.26;
use Data::Checks qw(� Num Str Object� ArrayRef HashRef Callable�);
CPAN Experiments�Data::Checks
A collection of value constraint assertions
use v5.26;
use Data::Checks qw( NumRange StrMatch );
NumRange(0, 100)->check( $ARGV[0] );
StrMatch(qr/a word/)->check( $ARGV[0] );
use v5.26;
use Data::Checks qw( NumRange StrEq Any );
Any(StrEq("nothing"), NumRange(0, 100))
->check( $ARGV[0] );
use v5.26;
use Data::Checks qw( NumRange StrEq );
(StrEq("nothing") | NumRange(0, 100))
->check( $ARGV[0] );
CPAN Experiments�Data::Checks
A collection of value constraint assertions
sub ping ( $target,� :$count :Checked(StrEq("nothing")|NumRange(0, 100))�) {
...
}
class Point {
field $x :Checked(StrEq("nothing")|NumRange(0, 100))� :param;
...
}
TYPES
CPAN Experiments�Syntax::Operator::Is
Value constraint checking as a boolean operator
use v5.26;
use Data::Checks qw( Num );
if( Num()->check( $ARGV[0] ) ) {� say "OK";�}
else {� say "Bad";�}
use v5.38;
use Syntax::Operator::Is;
use Data::Checks qw( Num );
if( $ARGV[0] is Num ) {� say "OK";�}
else {� say "Bad";�}
CPAN Experiments�Syntax::Operator::Is
Value constraint checking as a boolean operator
use v5.38;
use Test2::V0;
use Syntax::Operator::Is is => { -as => "satisfies" };
...
is( 123 satisfies Num, 'Num is testable' );
done_testing;
CPAN Experiments�Syntax::Keyword::Defer
Run code at scope exit
use v5.18;
use Syntax::Keyword::Defer;
my $dbh = Database->open( $path );
defer { $dbh->close; }
...
use v5.18;
use Syntax::Keyword::Try;
my $dbh;
try {
$dbh = Database->open( $path );
...
}
finally {
$dbh->close;
}
CPAN Experiments�Syntax::Operator::Eqr
Equality comparisons that are aware of undef and regexps
use v5.38;
use Syntax::Operator::Eqr;
my $str = ...;
if ( $str eqr undef ) { say "Is undef"; }
elsif( $str eqr "" ) { say "Is empty"; }
elsif( $str eqr qr/\d/ ) { say "Is a number"; }
else { say "Is non-empty"; }
CPAN Experiments
All these things possible because:
Core mechanisms designed to support experimentation in 3rd-party modules
CPAN Experiments�Easily Composable
Reflexive mechanisms in the parser
use v5.38;
use Syntax::Keyword::Match;
use Syntax::Operator::Eqr;
match( $str : eqr ) {
case( undef ) { say "Is undef"; }
case( "" ) { say "Is empty"; }
case( qr/\d/ ) { say "Is a number"; }
default { say "Is non-empty"; }
}
CPAN Experiments�Easily Composable
Reflexive mechanisms in the parser
use v5.38;
use Syntax::Keyword::Match;
use Syntax::Operator::Is;
use Data::Checks qw( StrEq Num );
match( $str : is ) {
case( StrEq("") ) { say "Is empty"; }
case( Num ) { say "Is a number"; }
default { say "Is non-empty"; }
}
CPAN Experiments�Static Grammar
Defined by data structures, not behavioural code
XPK_PARENS( /* ( EXPR : OP ) */
XPK_TERMEXPR_SCALARCTX, XPK_COLON, XPK_INFIX_MATCH_NOSMART
),
XPK_BRACES( /* { blocks... } */
XPK_REPEATED( /* case (EXPR) {BLOCK} */
XPK_COMMALIST(
XPK_KEYWORD("case"),
XPK_OPTIONAL( XPK_KEYWORD("if") ),
XPK_PARENS( XPK_TERMEXPR_SCALARCTX )
),
XPK_BLOCK
),
XPK_OPTIONAL( /* default { ... } */
XPK_KEYWORD("default"), XPK_BLOCK
)
)
Perl in 2030
Migrate more of those stable CPAN experiments into core
PPC process
Other Ideas
Other Ideas�:void, :scalar sub attributes
Attributes to force the ambient context of a subroutine
use v5.36;
sub note ( $message ) {
say "Note: $message";
}
say note("before"), "middle", note("after");
$ perl ...
Note: before
Note: after
1middle1
Other Ideas�:void, :scalar sub attributes
Attributes to force the ambient context of a subroutine
use v5.xx;
sub note :void ( $message ) {
say "Note: $message";
}
say note("before"), "middle", note("after");
$ perl ...
Note: before
Note: after
middle
Other Ideas�Phaser Expressions
Evaluate an expression earlier and inline a constant
use v5.10;
use constant DEBUG => $ENV{DEBUG};
if( DEBUG ) {� say "About to do the thing...";
}
use v5.xx;
if( BEGIN $ENV{DEBUG} ) {� say "About to do the thing...";
}
Other Ideas�Phaser Expressions
Evaluate an expression earlier and inline a constant
use v5.18;
use Syntax::Keyword::Match;
match($colour : ==) {
case(getcolour "red") { ... }
case(getcolour "green") { ... }
}
use v5.xx;
use Syntax::Keyword::Match;
match($colour : ==) {
case(BEGIN getcolour "red") { ... }
case(BEGIN getcolour "green") { ... }
}
Other Ideas�Errors and Warnings as Objects
More information out of them at runtime
Permitting More Extensibility
Allow more CPAN experimentation with more stuff
Permitting More Extensibility�Overload v2
Permit more kinds of operation to be overloadable
See also: overload::substr
use v5.xx;
use String::Tagged;
my $str = String::Tagged->new( "Hello, world",
message => 1,
);
my ( $word ) = $str =~ m/(\w+)/;
Permitting More Extensibility�Attributes v2
Interrupt the parser at compiletime
Probably to apply a Hook
Attributes in more places
Signature parameters
PPC0024� https://github.com/Perl/PPCs/blob/main/ppcs/ppc0024-signature-named-parameters.md
Permitting More Extensibility�Hooks
Perl has "Magic", which adds behaviour to scalar variables
struct {
int (*get) (SV *sv, MAGIC *mg);
int (*set) (SV *sv, MAGIC *mg);
int (*len) (SV *sv, MAGIC *mg);
int (*clear) (SV *sv, MAGIC *mg);
int (*free) (SV *sv, MAGIC *mg);
};
Permitting More Extensibility�Hooks
Magic is both "too much" and "too little"
Magic as side-annotations
free, maybe dup
Special-cases in perl core
overload, tie, vstring, ...
Permitting More Extensibility�Hooks
Hierarchy of shapes
struct BaseHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook *hk);
int (*clone) (SV *osv, SV *nsv, Hook *hk,� CLONE_PARAMS *params);
};
struct ValueHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook*hk);
int (*clone) (SV *osv, SV *nsv, ...
int (*copy) (SV *osv, SV *nsv, Hook *hk);
};
struct ScalarHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook*hk);
int (*clone) (SV *osv, SV *nsv, ...
int (*get) (SV *sv, Hook *hk);
int (*set) (SV *sv, Hook *hk);
int (*clear) (SV *sv, Hook *hk);
};
Permitting More Extensibility�Hooks
Extend the behaviour of things that aren't just scalar variables
struct ArrayHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook*hk);
int (*clone) (SV *osv, SV *nsv, ...
...
};
struct HashHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook*hk);
int (*clone) (SV *osv, SV *nsv, ...
...
};
struct CodeHook {
U32 ver;
U32 flags;
int (*free) (SV *sv, Hook*hk);
int (*clone) (SV *osv, SV *nsv, ...
...
};
See Also
See Also
CPAN:
Data::Checks
Future::AsyncAwait
List::Keywords
Object::Pad
Object::Pad::FieldAttr::Checked
Signature::Attribute::Checked
Sublike::Extended
Syntax::Keyword::Defer
Syntax::Keyword::Match
Syntax::Keyword::Try
Syntax::Operator::Equ
Syntax::Operator::Eqr
Syntax::Operator::In
Syntax::Operator::Is
Syntax::Operator::Zip
Thank You
Questions?
NO