SlideShare a Scribd company logo
1 of 69
Download to read offline
Evolution of OOP:
mro for EVERY::LAST one of us!
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
OOP is not an oxymoron.
Conway’s Object Oriented Programming.
Perl’s OO is flexible, adaptable.
Allowed 20+ years of advances.
OOP is not an oxymoron.
Conway’s Object Oriented Programming.
Perl’s OO is flexible, adaptable.
Allowed 20+ years of advances.
Largely through evolution.
Example: NEXT
NEXT::Foo
SUPER with logic
EVERY::foo
EVERY::LAST::foo
Destructor & Constructor chaining.
Redispatch down and up the chain is automagical.
EVERY::LAST
Lazyness: Do something once.
Perly ‘new’ is generic:
sub new
{
my $proto = shift;
my $obj = $proto->construct;
$obj->EVERY::LAST::initialize( @_ );
$obj
}
EVERY::LAST
Lazyness: Do something once.
Initializers don’t have to daisy-chain.
sub new
{
my $proto = shift;
my $obj = $proto->construct;
$obj->EVERY::LAST::initialize( @_ );
$obj
}
EVERY
Lazyness: Do something once.
Neither do destructors.
DESTROY
{
my $obj = shift;
$obj->EVERY::cleanup;
$obj
}
Evolution: mro
Offers “c3” instead of depth-first search.
Saner, more predictable.
Whole lot faster than NEXT.
mro lacks EVERY & EVERY::LAST
It does have “maybe_next”.
Requires explicit daisy chain:
sub initialize
{
my $obj = shift;
...
$obj->mro::maybe_next
}
Fix:
Hubris
Fix: mro::EVERY
Installs two pseudo-classes:
EVERY
EVERY::LAST
Dispatch down/up the inheritence tree.
Order defined by mro.
Fix one: mro::EVERY
package Frobnicate;
use mro::EVERY;
sub new
{
my $frob = &construct;
$frob->EVERY::LAST::initialize( @_ );
$frob
}
Looks like NEXT.
Fix one: mro::EVERY
Q: How to redispatch random subs?
Fix one: mro::EVERY
Q: How to redispatch random subs?
A: The magic of AUTOLOAD.
Fix one: mro::EVERY
Q: How to redispatch random subs?
A: The magic of AUTOLOAD.
PBP be damned...
Start with mro
mro::get_linear_isa
Resolves package “isa”.
Uses depth-first or “c3”.
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD =~ m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD = m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘EVERY::bar’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD = m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD = m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD = m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
AUTOLOAD does the dispatch
$foo->EVERY::bar( @blort );
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my ( $name ) = $AUTOLOAD = m{ (w+) $}x;
my $proto = shift;
for my $pkg ( $proto->mro::get_linear_isa->@* )
...
}
Finding a method
Most common way to look: can().
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = $pkg->can( $name )
or next;
...
}
Finding a method
Returns inherited $name, not declared.
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = $pkg->can( $name )
or next;
...
}
Finding a method
Symbol::qualify_to_ref.
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
...
}
Finding a method
Subref when it’s defined in the package.
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
...
}
Redispatching a method.
Perl has first-class subs.
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
$proto->$sub( @_ );
}
Redispatching a method.
Doesn’t handle AUTOLOAD!
for my $pkg ( $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
$proto->$sub( @_ );
}
EVERY::LAST dispatchs up the tree
Not much difference:
for my $pkg ( reverse $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
...
}
for my $pkg ( reverse $class->mro::get_linear_isa->@* )
{
my $sub = *{ qualify_to_ref $name => $pkg }{ CODE }
or next;
...
}
Avoiding “Red Flags”
Cut+Paste is a mistake.
Avoiding “Red Flags”
my $methodology
= sub
{
my ( $proto, $name ) = @_;
map
{
*{ qualify_to_ref $name => $_ }{ CODE } // ()
}
$proto->mro::get_linear_isa->@*
};
Package the re-usable portion in a utility sub.
Avoiding “Red Flags”
package EVERY;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my $proto = shift;
my $name = ( split ‘::’, $AUTOLOAD )[-1];
$proto->$_( @_ )
for uniq $methodology->($proto, $name)
}
List of subs in mro-order.
Avoiding “Red Flags”
package EVERY::LAST;
our $AUTOLOAD = ‘’;
sub AUTOLOAD
{
my $proto = shift;
my $name = ( split ‘::’, $AUTOLOAD )[-1];
$proto->$_( @_ )
for uniq reverse $methodology->($proto, $name)
}
Reverse the order for Every::Last
Avoiding “Red Flags”
for uniq $methodology->($proto, $name);
for uniq reverse $methodology->($proto, $name);
Avoiding “Red Flags”
Avoid re-dispatching identical methods.
use Foo qw( bar );
Only want to dispatch it once.
for uniq $methodology->($proto, $name);
for uniq reverse $methodology->($proto, $name);
Avoiding “Red Flags”
EVERY uses most-derived.
First defined method looking down the tree.
Useful for destructors peeling off layers.
EVERY::LAST uses least-derived.
Constructor-ish code handled by base classes.
for uniq $methodology->($proto, $name);
for uniq reverse $methodology->($proto, $name);
Handling AUTOLOAD
What if the package doesn’t define $name?
Uses its own AUTOLOAD instead?
# $name isn’t AUTOLOAD!
*{ qualify_to_ref $name => $_ }{ CODE } // ()
Handling AUTOLOAD
Requires an co-operating ‘can’ operator.
More expsive: you have to ask for it.
use mro::EVERY qw( autoload );
*{ qualify_to_ref $name => $_ }{ CODE }
or
do
{
...
}
Doing the can can()
package Yours;
our $AUTOLOAD = ‘’;
sub AUTOLOAD { … }
my @names = qw( this that other );
my %auto_can = map { ( $_ => &AUTOLOAD ) } @names;
sub can
{
my ( $proto, $name ) = @_;
$proto->can( $name ) or $auto_can{ $name }
}
Doing the can can()
package Yours;
our $AUTOLOAD = ‘’;
sub AUTOLOAD { … }
my @names = qw( this that other );
my %auto_can = map { ( $_ => &AUTOLOAD ) } @names;
sub can
{
my ( $proto, $name ) = @_;
$proto->can( $name ) or $auto_can{ $name }
}
Doing the can can()
package Yours;
our $AUTOLOAD = ‘’;
sub AUTOLOAD { … }
my @names = qw( this that other );
my %auto_can = map { ( $_ => &AUTOLOAD ) } @names;
sub can
{
my ( $proto, $name ) = @_;
$proto->can( $name ) or $auto_can{ $name }
}
Doing the can can()
package Yours;
our $AUTOLOAD = ‘’;
sub AUTOLOAD { … }
my @names = qw( this that other );
my %auto_can = map { ( $_ => &AUTOLOAD ) } @names;
sub can
{
my ( $proto, $name ) = @_;
$proto->can( $name ) or $auto_can{ $name }
}
map
{
*{ qualify_to_ref $name, $_ }{CODE}
or do
{
local *{qualify_to_ref ISA => $_} = [];
$_->can( $name )
? $name
: ()
}
}
$proto->mro::get_linear_isa->@*;
Dispatching AUTOLOAD
map
{
*{ qualify_to_ref $name, $_ }{CODE}
or do
{
local *{qualify_to_ref ISA => $_} = [];
$_->can( $name )
? $name
: ()
}
}
$proto->mro::get_linear_isa->@*;
Dispatching AUTOLOAD
map
{
*{ qualify_to_ref $name, $_ }{CODE}
or do
{
local *{qualify_to_ref ISA => $_} = [];
$_->can( $name )
? $name
: ()
}
}
$proto->mro::get_linear_isa->@*;
Dispatching AUTOLOAD
Dispatching AUTOLOAD
Yes, $name isn’t qualified.
Required for Perl to set $AUTOLOAD.
Point of AUTOLOAD is a catch-all.
Stacked AUTOLOAD calls are rare.
Dispatching AUTOLOAD
Alternative: dispatch with a closure.
Pre-load $AUTOLOAD with qualify_to_ref.
Dispatch via subref.
Dispatching AUTOLOAD
if( my $sub = $_->can( $name ) )
{
my $ref = qualify_to_ref AUTOLOAD => $_;
sub
{
*$ref = $name;
goto &$sub;
}
...
Module is small
Main package is just a pair of maps.
Pseudo-classes are just a pair of AUTOLOADS.
Fix two:
Lots of Hubris...
Fix two:
Hack NEXT.
Fix two:
Replace method lookup with mro.
Replace “ref $x” with “blessed $x” for object tests.
Replace “no strict” with qualify_to_ref...
Into the nextaverse
Two subs do the dirty work:
NEXT::ELSEWHERE::ancestors
NEXT::ELSEWHERE::ordered_ancestors
Into the nextaverse
Two subs do the dirty work:
NEXT::ELSEWHERE::ancestors
Depth-first-search in Pure Perl.
NEXT::ELSEWHERE::ordered_ancestors
c3[ish] in Pure Perl.
DFS in Pure Perl
Iterate @ISA chains with symbolic refs.
sub NEXT::ELSEWHERE::ancestors
{
my @inlist = shift;
my @outlist = ();
while (my $next = shift @inlist) {
push @outlist, $next;
no strict 'refs';
unshift @inlist, @{"$outlist[-1]::ISA"};
}
return @outlist;
}
DFS in Pure Perl
Using mro
sub NEXT::ELSEWHERE::ancestors
{
my $proto = shift;
@{ $proto->mro::get_linear_isa( ‘dfs’ ) }
}
DFS in Pure Perl
Using object syntax
sub NEXT::ELSEWHERE::ancestors
{
my $proto = shift;
$proto->mro::get_linear_isa( ‘dfs’ )->@*
}
Purly Perly c3[ish]
sub NEXT::ELSEWHERE::ordered_ancestors
{
my @inlist = shift;
my @outlist = ();
while (my $next = shift @inlist) {
push @outlist, $next;
no strict 'refs';
push @inlist, @{"$outlist[-1]::ISA"};
}
return sort { $a->isa($b) ? -1
: $b->isa($a) ? +1
: 0 } @outlist;
}
Purly Perly c3[ish]
sub NEXT::ELSEWHERE::ordered_ancestors
{
my $proto = shift;
$proto->mro::get_linear_isa->( ‘c3’ )->@*
}
Purly Perly c3[ish]
sub NEXT::ELSEWHERE::ordered_ancestors
{
my $proto = shift;
$proto->mro::get_linear_isa->( ‘c3’ )->@*
}
Well, Almost:
OA sorts depth-first, then left-most.
C3 sorts left-most, then depth-first.
Both constrain derived classes to precede base classes.
EVERY vs. EVERY::LAST
NEXT uses ancestors().
EVERY & EVERY::LAST use ordered_ancestors().
NEXT => mro( ‘dfs’ )
EVERY => mro( ‘c3’ )
Ideally both use mro from classes.
Fix for backwards uses
use NEXT qw( :backwards );
dfs in NEXT, c3 in EVERY.
Without it we use class specification in both.
Fix for backwards uses
my %backwards = ();
sub import
{
my $caller = caller;
for( @_ )
{
if( m{ :backwards } )
{
$backwards{ $caller } = undef;
}
}
}
Fix for backwards uses
sub NEXT::ELSEWHERE::ancestors
{
my $proto = shift;
exists $backwards{ blessed $proto }
? $proto->mro::get_linear_isa->( 'dfs' )->@*
: $proto->mro::get_linear_isa->@*
}
So what? It isn’t written in 5.8.8
Core modules have to be consistent.
Doesn’t mean they can’t evolve.
So what? It isn’t written in 5.8.8
Provide people what they want:
5.8 users get a 5.8 module.
Later users get a later module.
Bugs can be fixed everywhere.
Features get added to the more recent versions.
So what? It isn’t written in 5.8.8
Handled in Makfile.PL:
Install first directory <= $^V
with File::Copy::Recursive.
Added to FindBin:libs in 5.14.
NEXT-x.y.z
Makefile.PL
version
v5.8.8
lib
NEXT.pm
t
...
v5.10
lib
NEXT.pm # mro
t
...
v5.24
lib
NEXT.pm # ->@*
t
Yes, there is more than one way
Layering EVERY onto mro isn’t difficult.
Inserting mro() into NEXT isn’t that hard either.
Advancing modules with Perl is doable.
References
https://metacpan.org/pod/NEXT
https://metacpan.org/pod/mro::EVERY
Handling multiple versions:
https://metacpan.org/release/LEMBARK/FindBin-libs-
v3.0.1/source/Makefile.PL#L63
https://metacpan.org/pod/Module::FromPerlVer

More Related Content

Similar to mro-every.pdf

Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Masahiro Nagano
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
brian d foy
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
Seri Moth
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Masahiro Nagano
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
Taras Kalapun
 

Similar to mro-every.pdf (20)

Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 TokyoIntroduction to CloudForecast / YAPC::Asia 2010 Tokyo
Introduction to CloudForecast / YAPC::Asia 2010 Tokyo
 
wget.pl
wget.plwget.pl
wget.pl
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)
 
Developing applications for performance
Developing applications for performanceDeveloping applications for performance
Developing applications for performance
 
Taming Command Bus
Taming Command BusTaming Command Bus
Taming Command Bus
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
 
Daily notes
Daily notesDaily notes
Daily notes
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
 
Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?
 
Drupal Development (Part 2)
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 
Functional Pearls 4 (YAPC::EU::2009 remix)
Functional Pearls 4 (YAPC::EU::2009 remix)Functional Pearls 4 (YAPC::EU::2009 remix)
Functional Pearls 4 (YAPC::EU::2009 remix)
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it
 
Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.
 
Perl Web Client
Perl Web ClientPerl Web Client
Perl Web Client
 

More from Workhorse Computing

More from Workhorse Computing (20)

Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add UpParanormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add Up
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlGenerating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in Posgresql
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 
Findbin libs
Findbin libsFindbin libs
Findbin libs
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic Interpolation
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
Metadata-driven Testing
Metadata-driven TestingMetadata-driven Testing
Metadata-driven Testing
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
 
Smoking docker
Smoking dockerSmoking docker
Smoking docker
 
Getting Testy With Perl6
Getting Testy With Perl6Getting Testy With Perl6
Getting Testy With Perl6
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
 
Neatly folding-a-tree
Neatly folding-a-treeNeatly folding-a-tree
Neatly folding-a-tree
 
Light my-fuse
Light my-fuseLight my-fuse
Light my-fuse
 
Paranormal stats
Paranormal statsParanormal stats
Paranormal stats
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
 

Recently uploaded

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 

mro-every.pdf

  • 1. Evolution of OOP: mro for EVERY::LAST one of us! Steven Lembark Workhorse Computing lembark@wrkhors.com
  • 2. OOP is not an oxymoron. Conway’s Object Oriented Programming. Perl’s OO is flexible, adaptable. Allowed 20+ years of advances.
  • 3. OOP is not an oxymoron. Conway’s Object Oriented Programming. Perl’s OO is flexible, adaptable. Allowed 20+ years of advances. Largely through evolution.
  • 4. Example: NEXT NEXT::Foo SUPER with logic EVERY::foo EVERY::LAST::foo Destructor & Constructor chaining. Redispatch down and up the chain is automagical.
  • 5. EVERY::LAST Lazyness: Do something once. Perly ‘new’ is generic: sub new { my $proto = shift; my $obj = $proto->construct; $obj->EVERY::LAST::initialize( @_ ); $obj }
  • 6. EVERY::LAST Lazyness: Do something once. Initializers don’t have to daisy-chain. sub new { my $proto = shift; my $obj = $proto->construct; $obj->EVERY::LAST::initialize( @_ ); $obj }
  • 7. EVERY Lazyness: Do something once. Neither do destructors. DESTROY { my $obj = shift; $obj->EVERY::cleanup; $obj }
  • 8. Evolution: mro Offers “c3” instead of depth-first search. Saner, more predictable. Whole lot faster than NEXT.
  • 9. mro lacks EVERY & EVERY::LAST It does have “maybe_next”. Requires explicit daisy chain: sub initialize { my $obj = shift; ... $obj->mro::maybe_next }
  • 11. Fix: mro::EVERY Installs two pseudo-classes: EVERY EVERY::LAST Dispatch down/up the inheritence tree. Order defined by mro.
  • 12. Fix one: mro::EVERY package Frobnicate; use mro::EVERY; sub new { my $frob = &construct; $frob->EVERY::LAST::initialize( @_ ); $frob } Looks like NEXT.
  • 13. Fix one: mro::EVERY Q: How to redispatch random subs?
  • 14. Fix one: mro::EVERY Q: How to redispatch random subs? A: The magic of AUTOLOAD.
  • 15. Fix one: mro::EVERY Q: How to redispatch random subs? A: The magic of AUTOLOAD. PBP be damned...
  • 16. Start with mro mro::get_linear_isa Resolves package “isa”. Uses depth-first or “c3”.
  • 17. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD =~ m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 18. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD = m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 19. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘EVERY::bar’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD = m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 20. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD = m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 21. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD = m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 22. AUTOLOAD does the dispatch $foo->EVERY::bar( @blort ); package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my ( $name ) = $AUTOLOAD = m{ (w+) $}x; my $proto = shift; for my $pkg ( $proto->mro::get_linear_isa->@* ) ... }
  • 23. Finding a method Most common way to look: can(). for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = $pkg->can( $name ) or next; ... }
  • 24. Finding a method Returns inherited $name, not declared. for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = $pkg->can( $name ) or next; ... }
  • 25. Finding a method Symbol::qualify_to_ref. for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; ... }
  • 26. Finding a method Subref when it’s defined in the package. for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; ... }
  • 27. Redispatching a method. Perl has first-class subs. for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; $proto->$sub( @_ ); }
  • 28. Redispatching a method. Doesn’t handle AUTOLOAD! for my $pkg ( $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; $proto->$sub( @_ ); }
  • 29. EVERY::LAST dispatchs up the tree Not much difference: for my $pkg ( reverse $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; ... } for my $pkg ( reverse $class->mro::get_linear_isa->@* ) { my $sub = *{ qualify_to_ref $name => $pkg }{ CODE } or next; ... }
  • 31. Avoiding “Red Flags” my $methodology = sub { my ( $proto, $name ) = @_; map { *{ qualify_to_ref $name => $_ }{ CODE } // () } $proto->mro::get_linear_isa->@* }; Package the re-usable portion in a utility sub.
  • 32. Avoiding “Red Flags” package EVERY; our $AUTOLOAD = ‘’; sub AUTOLOAD { my $proto = shift; my $name = ( split ‘::’, $AUTOLOAD )[-1]; $proto->$_( @_ ) for uniq $methodology->($proto, $name) } List of subs in mro-order.
  • 33. Avoiding “Red Flags” package EVERY::LAST; our $AUTOLOAD = ‘’; sub AUTOLOAD { my $proto = shift; my $name = ( split ‘::’, $AUTOLOAD )[-1]; $proto->$_( @_ ) for uniq reverse $methodology->($proto, $name) } Reverse the order for Every::Last
  • 34. Avoiding “Red Flags” for uniq $methodology->($proto, $name); for uniq reverse $methodology->($proto, $name);
  • 35. Avoiding “Red Flags” Avoid re-dispatching identical methods. use Foo qw( bar ); Only want to dispatch it once. for uniq $methodology->($proto, $name); for uniq reverse $methodology->($proto, $name);
  • 36. Avoiding “Red Flags” EVERY uses most-derived. First defined method looking down the tree. Useful for destructors peeling off layers. EVERY::LAST uses least-derived. Constructor-ish code handled by base classes. for uniq $methodology->($proto, $name); for uniq reverse $methodology->($proto, $name);
  • 37. Handling AUTOLOAD What if the package doesn’t define $name? Uses its own AUTOLOAD instead? # $name isn’t AUTOLOAD! *{ qualify_to_ref $name => $_ }{ CODE } // ()
  • 38. Handling AUTOLOAD Requires an co-operating ‘can’ operator. More expsive: you have to ask for it. use mro::EVERY qw( autoload ); *{ qualify_to_ref $name => $_ }{ CODE } or do { ... }
  • 39. Doing the can can() package Yours; our $AUTOLOAD = ‘’; sub AUTOLOAD { … } my @names = qw( this that other ); my %auto_can = map { ( $_ => &AUTOLOAD ) } @names; sub can { my ( $proto, $name ) = @_; $proto->can( $name ) or $auto_can{ $name } }
  • 40. Doing the can can() package Yours; our $AUTOLOAD = ‘’; sub AUTOLOAD { … } my @names = qw( this that other ); my %auto_can = map { ( $_ => &AUTOLOAD ) } @names; sub can { my ( $proto, $name ) = @_; $proto->can( $name ) or $auto_can{ $name } }
  • 41. Doing the can can() package Yours; our $AUTOLOAD = ‘’; sub AUTOLOAD { … } my @names = qw( this that other ); my %auto_can = map { ( $_ => &AUTOLOAD ) } @names; sub can { my ( $proto, $name ) = @_; $proto->can( $name ) or $auto_can{ $name } }
  • 42. Doing the can can() package Yours; our $AUTOLOAD = ‘’; sub AUTOLOAD { … } my @names = qw( this that other ); my %auto_can = map { ( $_ => &AUTOLOAD ) } @names; sub can { my ( $proto, $name ) = @_; $proto->can( $name ) or $auto_can{ $name } }
  • 43. map { *{ qualify_to_ref $name, $_ }{CODE} or do { local *{qualify_to_ref ISA => $_} = []; $_->can( $name ) ? $name : () } } $proto->mro::get_linear_isa->@*; Dispatching AUTOLOAD
  • 44. map { *{ qualify_to_ref $name, $_ }{CODE} or do { local *{qualify_to_ref ISA => $_} = []; $_->can( $name ) ? $name : () } } $proto->mro::get_linear_isa->@*; Dispatching AUTOLOAD
  • 45. map { *{ qualify_to_ref $name, $_ }{CODE} or do { local *{qualify_to_ref ISA => $_} = []; $_->can( $name ) ? $name : () } } $proto->mro::get_linear_isa->@*; Dispatching AUTOLOAD
  • 46. Dispatching AUTOLOAD Yes, $name isn’t qualified. Required for Perl to set $AUTOLOAD. Point of AUTOLOAD is a catch-all. Stacked AUTOLOAD calls are rare.
  • 47. Dispatching AUTOLOAD Alternative: dispatch with a closure. Pre-load $AUTOLOAD with qualify_to_ref. Dispatch via subref.
  • 48. Dispatching AUTOLOAD if( my $sub = $_->can( $name ) ) { my $ref = qualify_to_ref AUTOLOAD => $_; sub { *$ref = $name; goto &$sub; } ...
  • 49. Module is small Main package is just a pair of maps. Pseudo-classes are just a pair of AUTOLOADS.
  • 50. Fix two: Lots of Hubris...
  • 52. Fix two: Replace method lookup with mro. Replace “ref $x” with “blessed $x” for object tests. Replace “no strict” with qualify_to_ref...
  • 53. Into the nextaverse Two subs do the dirty work: NEXT::ELSEWHERE::ancestors NEXT::ELSEWHERE::ordered_ancestors
  • 54. Into the nextaverse Two subs do the dirty work: NEXT::ELSEWHERE::ancestors Depth-first-search in Pure Perl. NEXT::ELSEWHERE::ordered_ancestors c3[ish] in Pure Perl.
  • 55. DFS in Pure Perl Iterate @ISA chains with symbolic refs. sub NEXT::ELSEWHERE::ancestors { my @inlist = shift; my @outlist = (); while (my $next = shift @inlist) { push @outlist, $next; no strict 'refs'; unshift @inlist, @{"$outlist[-1]::ISA"}; } return @outlist; }
  • 56. DFS in Pure Perl Using mro sub NEXT::ELSEWHERE::ancestors { my $proto = shift; @{ $proto->mro::get_linear_isa( ‘dfs’ ) } }
  • 57. DFS in Pure Perl Using object syntax sub NEXT::ELSEWHERE::ancestors { my $proto = shift; $proto->mro::get_linear_isa( ‘dfs’ )->@* }
  • 58. Purly Perly c3[ish] sub NEXT::ELSEWHERE::ordered_ancestors { my @inlist = shift; my @outlist = (); while (my $next = shift @inlist) { push @outlist, $next; no strict 'refs'; push @inlist, @{"$outlist[-1]::ISA"}; } return sort { $a->isa($b) ? -1 : $b->isa($a) ? +1 : 0 } @outlist; }
  • 59. Purly Perly c3[ish] sub NEXT::ELSEWHERE::ordered_ancestors { my $proto = shift; $proto->mro::get_linear_isa->( ‘c3’ )->@* }
  • 60. Purly Perly c3[ish] sub NEXT::ELSEWHERE::ordered_ancestors { my $proto = shift; $proto->mro::get_linear_isa->( ‘c3’ )->@* } Well, Almost: OA sorts depth-first, then left-most. C3 sorts left-most, then depth-first. Both constrain derived classes to precede base classes.
  • 61. EVERY vs. EVERY::LAST NEXT uses ancestors(). EVERY & EVERY::LAST use ordered_ancestors(). NEXT => mro( ‘dfs’ ) EVERY => mro( ‘c3’ ) Ideally both use mro from classes.
  • 62. Fix for backwards uses use NEXT qw( :backwards ); dfs in NEXT, c3 in EVERY. Without it we use class specification in both.
  • 63. Fix for backwards uses my %backwards = (); sub import { my $caller = caller; for( @_ ) { if( m{ :backwards } ) { $backwards{ $caller } = undef; } } }
  • 64. Fix for backwards uses sub NEXT::ELSEWHERE::ancestors { my $proto = shift; exists $backwards{ blessed $proto } ? $proto->mro::get_linear_isa->( 'dfs' )->@* : $proto->mro::get_linear_isa->@* }
  • 65. So what? It isn’t written in 5.8.8 Core modules have to be consistent. Doesn’t mean they can’t evolve.
  • 66. So what? It isn’t written in 5.8.8 Provide people what they want: 5.8 users get a 5.8 module. Later users get a later module. Bugs can be fixed everywhere. Features get added to the more recent versions.
  • 67. So what? It isn’t written in 5.8.8 Handled in Makfile.PL: Install first directory <= $^V with File::Copy::Recursive. Added to FindBin:libs in 5.14. NEXT-x.y.z Makefile.PL version v5.8.8 lib NEXT.pm t ... v5.10 lib NEXT.pm # mro t ... v5.24 lib NEXT.pm # ->@* t
  • 68. Yes, there is more than one way Layering EVERY onto mro isn’t difficult. Inserting mro() into NEXT isn’t that hard either. Advancing modules with Perl is doable.