1 of 72

Perl in 2025

Paul “LeoNerd” Evans (PEVANS)

2 of 72

Who Am I?

CPAN "PEVANS"� https://metacpan.org/author/PEVANS

  • Big modules - Future, IO::Async, ...
  • Core modules - Socket, List::Util

TPF Grantee

  • Future::AsyncAwait

3 of 72

Who Am I?

IRC - <LeoNerd> on

Freenode

irc.perl.org

Meet people in community

4 of 72

Perl in 2020

2020 Perl Advent Calendar

Writing Perl in 2020

    • Signatures
    • isa
    • Syntax Modules

5 of 72

Perl in 2020�Signatures from Perl 5.20+

use Carp;

sub get_page_title {

my ($url) = @_;

...

}

use feature qw(signatures);

sub get_page_title($url) {

...

}

use feature qw(signatures);

my $compare = sub($x) { $x > 0 };

use feature qw(signatures);

my $compare = sub($x) { $x > 0 };

my $compare = sub { my ($x) = @_; $x > 0 };

my $compare = sub { $_[0] > 0 };

6 of 72

Perl in 2020�isa from Perl 5.32+

use Scalar::Util qw(blessed);

if(blessed $obj and $obj->isa("Butterfly")) {

...

}

use Safe::Isa;

if($obj->$_isa("Butterfly")) {

...

}

use feature qw(isa);

if($obj isa Butterfly) {

...

}

7 of 72

Perl in 2020�Exception Handling

my $ok = eval {

my $response = GET("http://my-site-here.com");

say "Got a response";

1;

};

if(!$ok) {

my $e = $@;

print STDERR "It failed: $e\n";

}

my $ok = eval {

my $response = GET("http://my-site-here.com");

say "Got a response";

1;

};

if(!$ok) {

my $e = $@;

print STDERR "It failed: $e\n";

}

sub get_page_title($url) {

my $ok = eval {

my $response = GET($url);

return $response->page_title;

};

...

8 of 72

Perl in 2020�Exception Handling

my $ok = eval {

my $response = GET("http://my-site-here.com");

say "Got a response";

1;

};

if(!$ok) {

my $e = $@;

print STDERR "It failed: $e\n";

}

use Syntax::Keyword::Try;

try {

my $response = GET("http://my-site-here.com");

say "Got a response";

}

catch($e) {

print STDERR "It failed: $e\n";

}

use Syntax::Keyword::Try;

sub get_page_title($url) {

try {

my $response = GET($url);

return $response->page_title;

}

catch($e) {

return undef;

}

}

9 of 72

Perl in 2020�Asynchronous Programming

sub _cached_read

{

my $self = shift;

return $self->{_bytes} if $self->{_bytes};

return $self->_read->then(sub {

($self->{_bytes}) = @_;

return Future->done($self->{_bytes});

});

}

use Future::AsyncAwait;

async sub _cached_read

{

my $self = shift;

return $self->{_bytes} //= await $self->_read;

}

10 of 72

Perl in 2020�Object classes

package Point {

sub new {

my $class = shift;

bless {x => $_[0], y => $_[1]}, $class;

}

sub describe {

my $self = shift;

say "A point at ($self->{x}, $self->{y})";

}

}

use Object::Pad;

class Point {

has $x; has $y;

BUILD { ($x, $y) = @_; }

method describe { say "A point at ($x, $y)"; }

}

11 of 72

Perl in 2020�Object classes and Cor

Inspired by Cor by Curtis Poe (aka "Ovid")�https://github.com/Ovid/Cor/wiki

Cor's idea to Object::Pad's implementation

Cor - The Future of OO in Perlhttps://fosdem.org/2021/schedule/event/future_of_oo_perl_cor/

12 of 72

Perl in 2020�Combining Syntax Modules

use Future::AsyncAwait;

use Syntax::Keyword::Try;

async sub get_page_images($url)

{

try {

return (await GET($url))->images;

}

catch {

return ();

}

}

use Future::AsyncAwait;

use Object::Pad;

...

has $_bytes;

async method _cached_read

{

return $_bytes //= await $self->_read;

}

sub _cached_read

{

my $self = shift;

return $self->{_bytes} if $self->{_bytes};

return $self->_read->then(sub {

($self->{_bytes}) = @_;

return Future->done($self->{_bytes});

});

}

13 of 72

Perl in 2025

Some complete

Some more vague

Some can be CPAN modules

Some must be core

14 of 72

Perl in 2025

A lot of them combine together

Feedback welcome

Let's BEGIN

15 of 72

Perl in 2025�No more smartmatch

Imported from Perl 6 (as was)

16 of 72

Perl in 2025�No more smartmatch

Imported from Raku

Raku types

#!/usr/bin/raku

my $str = "5";

my $num = 5;

say "str is $str and num is $num";

# types remain unchanged

17 of 72

Perl in 2025�No more smartmatch

Imported from Raku

Perl types

#!/usr/bin/perl

my $str = "5";

my $num = 5;

say "str is $str and num is $num";

# $num is now both number and string

18 of 72

Perl in 2025�No more smartmatch

Imported from Raku

Unpredictable rules

5 ~~ 5.0

5 ~~ "5.0"

"5" ~~ "5.0"

true

true

false

19 of 72

Perl in 2025�No more smartmatch

Imported from Raku

Unpredictable rules

5 ~~ [1..10]

"x" ~~ {x => 12, y => 34}

"a" ~~ {x => 12, y => 34}

true

true

false

20 of 72

Perl in 2025�No more smartmatch

Imported from Raku

Unpredictable rules

5 ~~ sub { $_ % 2 == 0 }

6 ~~ sub { $_ % 2 == 0 }

%ENV ~~ sub { $_ % 2 == 0 }

false

true

???

21 of 72

Perl in 2025�No more smartmatch

given/when is useful but relies on ~~

use feature qw(switch);

given($var) {

when("abc") { ... }

when("def") { ... }

when("1.0") { ... }

otherwise { ... }

}

if ($var ~~ "abc") { ... }

elsif($var ~~ "def") { ... }

elsif($var ~~ "1.0") { ... }

else { ... }

22 of 72

Perl in 2025�match/case

if ($var eq "abc") { ... }

elsif($var eq "def") { ... }

elsif($var eq "1.0") { ... }

else { ... }

use Hypothetical::MatchCase;

match($var : eq) {

case("abc") { ... }

case("def") { ... }

case("1.0") { ... }

otherwise { ... }

}

use Hypothetical::MatchCase;

match($var : eq) {

case("abc") { ... }

case("def") { ... }

case("1.0") { ... }

otherwise { ... }

}

use Hypothetical::MatchCase;

match($var : eq) {

case("abc") { ... }

case("def") { ... }

case("1.0") { ... }

otherwise { ... }

}

23 of 72

Perl in 2025�match/case

if ($var == 1) { ... }

elsif($var == 2) { ... }

elsif($var == 3) { ... }

else { ... }

use Hypothetical::MatchCase;

match($var : ==) {

case(1) { ... }

case(2) { ... }

case(3) { ... }

otherwise { ... }

}

24 of 72

Perl in 2025�match/case

Compare to Switch::Plain

use Switch::Plain;

sswitch($var) {

case "abc": { ... }

case "def": { ... }

case "1.0": { ... }

default: { ... }

}

use Switch::Plain;

nswitch($var) {

case 1: { ... }

case 2: { ... }

case 3: { ... }

default: { ... }

}

25 of 72

Perl in 2025�match/case

if ($str =~ m/^foo/) { ... }

elsif($str =~ m/^bar/) { ... }

elsif($str =~ m/^qux/) { ... }

else { ... }

use Hypothetical::MatchCase;

match($str : =~) {

case(m/^foo/) { ... }

case(m/^bar/) { ... }

case(m/^qux/) { ... }

otherwise { ... }

}

26 of 72

Perl in 2025�match/case

if ($fruit isa Apple) { ... }

elsif($fruit isa Orange) { ... }

elsif($fruit isa Tomato) { ... }

else { ... }

use Hypothetical::MatchCase;

match($fruit : isa) {

case(Apple) { ... }

case(Orange) { ... }

case(Tomato) { ... }

otherwise { ... }

}

27 of 72

Perl in 2025�match/case

use Hypothetical::MatchCase;

match($n : ==) {

case(0) { say "No items" }

case(1) { say "An item" }

case(2,3,4) { say "Few items" }

otherwise { say "Many items" }

}

if ($n == 0) { say "No items" }

elsif($n == 1) { say "An item" }

elsif($n == 2 or $n == 3 or $n == 4)

{ say "Few items" }

else { say "Many items" }

28 of 72

Perl in 2025�match/case - some comments

Only constants for case(), no variables

Uniqueness can be checked at compile-time

More efficient operation

Fixed set of operators

eq, ==, =~, isa

29 of 72

Perl in 2025�match/case - open questions

Do we handle undef?

given($str) {

when(undef) { say "Undefined" }

when("") { say "Empty" }

when("abc") { say "A string" }

}

match($str : eq) {

case(undef) { say "Undefined" }

case("") { say "Empty" }

case("abc") { say "A string" }

}

Does it special-case?

if (!defined $str) { ... }

elsif($str eq "") { ... }

elsif($str eq "abc") { ... }

?

30 of 72

Perl in 2025�match/case - open questions

Do we handle undef?

match($str : eq) {

case(undef) { say "Undefined" }

case("") { say "Empty" }

case("abc") { say "A string" }

}

Do we need a new operator?

match($str : equ) {

case(undef) { say "Undefined" }

case("") { say "Empty" }

case("abc") { say "A string" }

}

$x equ $y

?

31 of 72

Perl in 2025�equ operator

undef equ undef # true

undef equ "anything" # false

undef equ undef # true

undef equ "anything" # false

undef equ "" # false

undef equ undef # true

undef equ "anything" # false

undef equ "" # false

"str" equ "str" # true

"abc" equ "def" # false

use warnings;

undef equ "anything" # silent

32 of 72

Perl in 2025�equ and === operators

undef equ undef # true

undef equ "anything" # false

undef equ "" # false

"str" equ "str" # true

"abc" equ "def" # false

undef === undef # true

undef === 100 # false

undef === 0 # false

200 === 200 # true

123 === 456 # false

33 of 72

Perl in 2025�equ and === operators

if(!defined $x and !defined $y or

defined $x and defined $y and $x eq $y) {

say "Same";

}

else {

say "Different";

}

if($x equ $y) {

say "Same";

}

else {

say "Different";

}

34 of 72

Perl in 2025�match/case - open questions

match($num : ==) {

case(1) { say "One" }

case(2,3,4,5,6,7,8,9)

{ say "Some" }

}

Do we handle ranges?

match($num : ==) {

case(1) { say "One" }

case(2..9) { say "Some" }

}

if ( $num == 1) { say "One" }

elsif( 2 <= $num <= 9) { say "Some" }

35 of 72

Perl in 2025�match/case - open questions

Do we handle ranges?

match($num : ==) {

case(1) { say "One" }

case(2..9) { say "Some" }

case(10..) { say "Lots" }

}

if ( $num == 1) { say "One" }

elsif( 2 <= $num <= 9) { say "Some" }

elsif(10 <= $num ) { say "Lots" }

36 of 72

Perl in 2025�match/case - open questions

Do we handle ranges?

match($num : ==) {

case(1) { say "One" }

case(2..9) { say "Some" }

case(10..) { say "Lots" }

}

Not really any-like now

match(2.5 : ==) {

case(0..9) { say "Lone digit" }

}

37 of 72

Perl in 2025�any as basic syntax

if ($n == 0) { say "No items" }

elsif($n == 1) { say "An item" }

elsif($n == 2 or $n == 3 or $n == 4)

{ say "Few items" }

else { say "Many items" }

use List::Util qw(any);

...

elsif(any {$n == $_} 2, 3, 4) { say "Few items" }

use List::Util qw(any);

...

elsif(any {$n == $_} 2, 3, 4) { say "Few items" }

38 of 72

Perl in 2025�any as basic syntax

if ($n == 0) { say "No items" }

elsif($n == 1) { say "An item" }

elsif($n == 2 or $n == 3 or $n == 4)

{ say "Few items" }

else { say "Many items" }

use Hypothetical::List::Ops qw(any);

...

elsif(any {$n == $_} 2, 3, 4) { say "Few items" }

39 of 72

Perl in 2025�all as basic syntax

use Hypothetical::List::Ops qw(all);

...

if(all {$_ < 100} @sizes) { say "All small" }

use Hypothetical::List::Ops qw(none);

...

if(none {$_ > 100} @sizes) { say "Nothing too big" }

40 of 72

Perl in 2025�in operator

use Hypothetical::List::Ops qw(any);

if(any {$n == $_} 2, 3, 4) { say "Few items" }

if($n in (2, 3, 4)) { say "Few items" }

41 of 72

Perl in 2025�in metaoperator

use Hypothetical::List::Ops qw(any);

if(any {$n == $_} 2, 3, 4) { say "Few items" }

use Hypothetical::List::Ops qw(in);

if($n in(==) (2, 3, 4)) { say "Few items" }

use Hypothetical::List::Ops qw(in);

if($n in(==) (2, 3, 4)) { say "Few items" }

if($n in<==> (2, 3, 4)) { say "Few items" }

use Hypothetical::List::Ops qw(in);

if($n in(==) (2, 3, 4)) { say "Few items" }

if($n in<==> (2, 3, 4)) { say "Few items" }

if($n in:== (2, 3, 4)) { say "Few items" }

use Hypothetical::List::Ops qw(any);

if(any {$n == $_} 2, 3, 4) { say "Few items" }

42 of 72

Perl in 2025�in metaoperator

use Hypothetical::List::Ops qw(in);

if($num in:== (2, 3, 4)) { say "Numerical" }

if($str in:eq ("ab", "cd")) { say "Stringy" }

my @patterns = (qr/^foo/, ...);�if($str in:=~ @patterns) { say "Regexp" }

my @classes = (Tomato, ...);�if($obj in:isa @classes) { say "Classy" }

use Hypothetical::List::Ops qw(in);

if($num in:=== (2, 3, 4)) ...

if($num in:equ ("ab", "cd")) ...

43 of 72

Perl in 2025�Checked list assignment

Signatures are sort-of like list unpack

use feature qw(signatures);

sub get_page_title($url) {

...

}

sub get_page_title {

my ($url) = @_;

...

}

sub get_page_title {

@_ >= 1 or croak "Too few arguments for subroutine";

@_ <= 1 or croak "Too many arguments for subroutine";

my ($url) = @_;

...

}

44 of 72

Perl in 2025�Checked list assignment

Signatures are sort-of like list unpack

use feature qw(signatures);

sub func($one, $two, $three = 3) {

...

}

sub func {

@_ >= 2 or croak "Too few arguments for subroutine";

@_ <= 3 or croak "Too many arguments for subroutine";

my $one = $_[0];

my $two = $_[1];

my $three = @_ > 2 ? $_[2] : 3;

...

45 of 72

Perl in 2025�Checked list assignment

use feature qw(bind);

my ($one, $two, $three = 3) := (1, 2);

use feature qw(bind);

my ($one, $two, $three = 3) := (1, 2);

my ($one, $two, $three = 3) := @values;

use feature qw(bind);

my ($one, $two, $three = 3) := (1, 2);

my ($one, $two, $three = 3) := @values;

my ($one, $two, $three = 3) := some_func();

use feature qw(let);

let ($one, $two, $three = 3) := some_func();

use Hypothetical::Let;

let ($one, $two, $three = 3) = some_func();

46 of 72

Perl in 2025�Checked list assignment

Signatures might gain named parameters

use feature qw(signatures);

sub set_rectangle(:$width, :$height) { ... }

set_rectangle(width => 10, height => 20);

use Hypothetical::Let;

let (:$width, :$height) = %rect;

my ($width, $height) = @rect{qw(width height)};

47 of 72

Perl in 2025�Checked list assignment

Signatures might gain isa assertions

use feature qw(signatures);

sub set_user($user isa User) { ... }

use Hypothetical::Let;

let ($user isa User) = @args;

48 of 72

Perl in 2025�Non-fatal list bind

use Hypothetical::Let;

let (:$width, :$height) = %rect;

use Hypothetical::Let;

if(maybelet (:$width, :$height) = %rect) {

Rectangle->new($width, $height);

}

use Hypothetical::Let;

while(maybelet ($item) = $coll->next) {

say "An item: $item";

}

49 of 72

Perl in 2025�Non-fatal list bind

use Hypothetical::Let;

while(maybelet ($item) = $coll->next) {

say "An item: $item";

}

maybelet ($item) = () # false

maybelet ($item) = ("thing") # true

maybelet ($item) = ("") # true

maybelet ($item) = (undef) # true

50 of 72

Perl in 2025�Twigils in Object::Pad

use Object::Pad;

class Point {

has $x; has $y;

BUILD { ($x, $y) = @_; }

method describe {

say "A point at ($x, $y)";

}

}

use Object::Pad;

class Point {

has $x; has $y;

BUILD { ($x, $y) = @_; }

method describe($z) {

say "A point at ($x, $y, $z)";

}

}

use Object::Pad;

class Point {

has $:x; has $:y;

BUILD { ($:x, $:y) = @_; }

method describe($z) {

say "A point at ($:x, $:y, $z)";

}

}

say "A point at ($self->{x}, $self->{y}, $z)";

51 of 72

Perl in 2025�Typing semantics

Types as static assertions

sub display_a_flag(Flag $flag) {

...

}

my string $str;

display_a_flag($str);

$ perl -c example.pl

Type mismatch for '$flag' argument to 'display_a_flag' (string cannot be a Flag) at example.pl line 123.

52 of 72

Perl in 2025�Typing semantics

Types as dynamic assertions

sub display_a_flag($flag isa Flag) {

...

}

my $str = "not a flag";

display_a_flag($str);

$ perl -c example.pl

example.pl syntax OK

$ perl example.pl

Type mismatch for '$flag' argument to display_a_flag (value "not a flag" cannot be a Flag) at example.pl line 123.

53 of 72

Perl in 2025�Typing semantics

Types as performance hints

sub display_the_flags(Flag @flags) {

my Palette $palette = Palette->new;

foreach my $flag (@flags) {

my @colours = $flag->get_colours;

$palette->add_colours(@colours);

}

...

}

54 of 72

Perl in 2025�Typing semantics

Types as static (compiletime) checks

Types as dynamic (runtime) checks

Types as performance hints

55 of 72

Perl in 2025�Typing semantics

Types as static (compiletime) checks

Types as dynamic (runtime) checks

Types as performance hints

56 of 72

Perl in 2025�Type assertions

use feature qw(signatures);

sub set_user($user isa User) { ... }

use feature qw(signatures types);

sub set_height($user is NonNegative) { ... }

use feature qw(typing);

subtype NonNegative is Numerical where { $_ >= 0 };

57 of 72

Perl in 2025�Type assertions

use feature qw(signatures);

sub set_user($user isa User) { ... }

use feature qw(signatures types);

sub set_flag($flag is MulticolouredFlag) { ... }

use feature qw(types);

subtype MulticolouredFlag isa Flag where

{ $_->colours > 1 };

58 of 72

Perl in 2025�Type assertions

use feature qw(let types);

let (:$height is Positive, :$width is Positive) := %rect;

use feature qw(types);

subtype Positive is Numerical where { $_ > 0 };

59 of 72

Perl in 2025�Type assertions

use feature qw(types);

subtype Negative is Numerical where { $_ < 0 };

subtype Positive is Numerical where { $_ > 0 };

use feature qw(match types);

match($num : is) {

case(Negative) { say "Less than zero" }

case(Positive) { say "Greater than zero" }

}

60 of 72

Perl in 2025�Type assertions

use feature qw(types);

subtype Positive is Numerical where { $_ > 0 };

use feature qw(types);

my ($x, $x) is Numerical;

my ($width, $height) is Positive;

61 of 72

Perl in 2025�Type assertions

use feature qw(types);

subtype Positive is Numerical where { $_ > 0 };

use feature qw(class types);

class Rectangle {

has $x is Numerical; has $y is Numerical;

has $width is Positive; has $height is Positive;

}

62 of 72

Perl in 2025�multi sub

use feature qw(isa signatures);

sub speak($animal) {

if ($animal isa Cow) { say "Moo" }

elsif($animal isa Sheep) { say "Baa" }

else { die "Cannot" }

}

use feature qw(isa match signatures);

sub speak($animal) {

match($animal : isa) {

case(Cow) { say "Moo" }

case(Sheep) { say "Baa" }

otherwise { die "Cannot" }

}

}

use Hypothetical::Multi::Dispatch;

multi sub speak($animal isa Cow) {

say "Moo";

}

multi sub speak($animal isa Sheep) {

say "Baa";

}

63 of 72

Perl in 2025�multi sub

use feature qw(class types);

use Hypothetical::Multi::Dispatch;

multi method speak_to($target isa Goose)

{

$self->say("Boo", target => $target);

}

use feature qw(class types);

use Future::AsyncAwait;

use Hypothetical::Multi::Dispatch;

multi async method speak_to($target isa Goose)

{

await $self->say("Boo", target => $target);

}

64 of 72

Additional Syntax

match/case

equ and === operators

any, all as operators

in metaoperator

let as generic list bind

Type assertions with is

multi sub

65 of 72

Additional Syntax

A few standalone ideas

Many of them work best in combination

isa, is, equ, ===

try/catch, match/case, signatures, let, multi sub

66 of 72

Additional Syntax

multi sub speak($animal isa Cow) {

say "Moo";

}

multi sub speak($animal isa Sheep) {

say "Baa";

}

class ByteReader;

has $_bytes;

async method _cached_read

{

return $_bytes //= await $self->_read;

}

if($num in:=== (2, 3, 4)) ...

if($num in:equ ("ab", "cd")) ...

match($num : ==) {

case(1) { say "One" }

case(2..9) { say "Some" }

case(10..) { say "Lots" }

}

while(maybelet ($item) = $coll->next) {

say "An item: $item";

}

67 of 72

Migration to core

Migrate "stablised" experiments into core perl

use feature qw(try);

try {

...

}

catch($e) {

...

}

use feature qw(class);

class Point {

has $x;

has $y;

method zero {

...

}

}

68 of 72

Migration to core�async/await in core?

Requires a Future representation

https://metacpan.org/pod/Future has about 40 methods

Mostly predates async/await

Core would get a smaller cut-down class

69 of 72

Migration to core�use VERSION

use v5.10;

turns on features like say, state

use v5.16;

turns on features like fc, __SUB__

70 of 72

Migration to core�use VERSION

use v5.36;

try {

...

}

catch($e) {

...

}

use v5.36;

match($str : eq) {

case("a") { ... }

case("b") { ... }

case("c") { ... }

}

use v5.40;

class Point {

has $x;

has $y;

method zero {

...

}

}

use v5.36;

if($n in:== @nums) { ... }

use v5.36;

let ($x, $y) := get_size();

use v5.40;

subtype Bestagon isa Shape where

{ $_->sides == 6 };

my $hexagon is Bestagon;

71 of 72

Migration to core�use VERSION

use v7;

try {

...

}

catch($e) {

...

}

use v7;

match($str : eq) {

case("a") { ... }

case("b") { ... }

case("c") { ... }

}

use v7;

class Point {

has $x;

has $y;

method zero {

...

}

}

use v7;

if($n in:== @nums) { ... }

use v7;

let ($x, $y) := get_size();

use v7;

subtype Bestagon isa Shape where

{ $_->sides == 6 };

my $hexagon is Bestagon;

72 of 72

Thank You

Live Q&A