Reflex - How Does It Work? (extended dance remix)

Post on 15-May-2015

3,229 views 1 download

Tags:

description

Most asynchronous Perl programming is unnecessarily dynamic. It conflicts with object orientation, and it reintroduces memory management issues that some of us learned Perl to escape.Reflex is a flexible, contemporary asynchronous library that embraces the latest developments in Perl object orientation. Asynchronous classes can be snapped together at coding time, reducing the amount of anonymous code that's often slung around at runtime. Methods are first-class callbacks in Reflex; they can be augmented and overridden using normal Perl OO. Mixing in Moose make things even better.This presentation is an expanded, more code-intensive version of my Perl Oasis talk. It will cover the 6.5 ways Reflex-based modules can be used, including anonymous callback and closure juggling, and mind-bogglingly powerful Moose-fueled OO crack. Imperative promises are included for people who just want to do one simple thing without mucking about with callbacks at all.

transcript

ReflexHow does it work?

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

Feedback, plx.

Who Does He Think He Is?

• Rocco Caputo or “rcaputo” most places.

• http://search.cpan.org/~rcaputo/

• https://github.com/rcaputo

• http://twitter.com/rcaputo

“The POE Guy”

⃠“The POE Guy”⃠

Curtis “Ovid” Poe

Edgar Allan Poe

Anne Decatur

Danielewski

The Other Committers• Adam Kennedy

• Benjamin Smith

• Casey West

• Chris Fedde

• Chris Williams

• David Davis

• David Webb

• Hinrik Örn Sigurðsson

• jmadler

• Jonathan Steinert

• Larwan Berke

• Martijn van Beers

• Matt Cashner

• Matt Sickler

• Perl Whore

• Philip Gwyn

• Tom Feist

• Yuval Kogman

The CPAN AuthorsAlejandro Imass • Alessandro Ranellucci • Anatoly Sharifulin • Andrew A. Chen • Andrew Hoying • Andrew Sterling Hanenkamp • Andrew V. Purshottam • Andy Grundman • Artur Bergman • Benjamin Trott • Brendan Beveridge • Chris Cobb • Chris Prather • Christian-Rolf Gruen • Curtis Hawthorne • Daisuke Maki • Daisuke Murase • Damien Krotkine • Dan McCormick • David Golden • David Snopek • Denis Pokataev • Dmitry Karasik • dmitry kim • Eriam Schaffter • Eric Waters • Erick Calder • George Nistorica • Greg Fast • Guillermo Roditi • Hans Dieter Pearcey • Ivan B. Serezhkin • J. J. Merelo Guervos • Jan Henning Thorsen • Jason McManus • Jeff Bisbee • Jeff Goff • Jerome Quelin • Johannes Plunien • Jonathan Ringstad • Jozef Kutej • Justin Hunter • Kazuhiro Osawa • Kevin L. Esteb • Kirill Miazine • Larry Shatzer Jr • Loic TROCHET • Marc Lehmann • Marc Mims • Mark A. Hershberger • Mark McConnell • Mark Morgan • Markus Mueller • Matthew O’Connor • Michael Ching • Michael R. Davis • Michael Schilli • Mike Fletcher • Mike Schroeder • Mischa Spiegelmock • MOCK • MSERGEANT • Nicholas Perez • Olivier ‘dolmen’ Mengue • Paul David Tinsley • Paul Driver • Paul Evans • Paul G Webster • Paul Visscher • Pavel Boldin • Pedro Melo • Peter Guzis • Przemyslaw Iskra • Rafael Kitover • Richard Clamp • Rob Bloodgood • Rob Partington • Robert ‘phaylon’ Sedlacek • Sawyer X • Scott Beck • Scott McCoy • Sean Egan • Sebastien Aperghis-Tramoni • Sergey Kotenko • Sergey Skvortsov • Sjors Gielen • Stephen Adkins • Steve James • Steve McNabb • Takeshi Miki • Tatsuhiko Miyagawa • Thiago Berlitz Rondon • Tony Cook • Torsten Raudssus • wb@95700.net • William Travis Holton • Yuji Suzuki • Yves Blusseau • Zoffix Znet

EOVERFLOWThe Users

Okay, me too.

Digression:See Digression

ReflexWhat Is It?

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

ReflexWhat Isn’t It?

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

What can’t you do with a drunken sailor?

Reflex is an only child waiting in

the park.

⃠Reflex is an only child waiting in

the park.⃠

Reflex isn’t an event loop.

CPAN already has too many

event loops.

Event loops are the means, not the ends.

Reflex is eventy without so much loopy.

Nor is Reflex an object system.

CPAN already has too many

object systems.

Reflex uses Moose

But Why?!“I am disappointed that after all this time we have no consensus on how to say in Perl ‘Class X has attribute Y’ when so many other languages have solutions that have freed their users’ minds up to move on to higher-level problems.”— Peter Scott, on the Perl 5 Porters Mailing List

But Why?!

• Moose lets me solve higher-level problems.

• Moose has sufficient adoption to survive.

• The Meta-Object Protocol is insanely useful.

• Moose will get better as native Perl OO improves.

ReflexWhat Is It?

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

The ORM of Event Loops!!

Marketing bullshit aside...

Reactive Program Building

Blocks

Building Blocks

Provided by Moose

Plus a Reactor provided by Your Favorite Event

Loop

Invisible Event Loop

Like ORMs hide SQL behind

objects...

ORM

DB

Reflex

The Events Can

Reflex hides event

loops behind

objects...

Reflex is Modern

POE

Reflex is Modern POE

• POE = Perl Object Environment

• Modern Perl objects are very different than 1998 Perl objects.

• POE has a lot of users.

• Start over with Reflex so POE remains compatible.

Reflex unifies eventy

interaction.

Rule 34 for Perl

If you can think of it, CPAN has a module for it.

TIMTOWTDI

If you can think of it, CPAN has 2+ incompatible modules for it...

TIMTOWTDI

... and someday you’ll need to

use both at once.

TIMTOWTDI

• There’s more than one way to pass events around.

• The “best” way... depends.

• Choosing poorly limits later options.

• Reflex supports any or all at once.

3 ½ Rules Make it Work

⁓ 1 ⁓Objects must not dictate callback mechanisms.

⁓ 1.5 ⁓Users define

how they receive callbacks.

⁓ 2 ⁓The base system must support all desired callback

types.

⁓ 3 ⁓Reflex must do

just enough work to be correct.

Reflex unifies eventy program

composition.

“How Eventy Programs are Put Together”

Static Composition

• Code is bolted together before running.

• Subclassing.

• Role composition.

• All pieces built and destroyed together.

• Most eventy abstractions ignore this.

Dynamic Composition

• Event watchers are created,

• related (has-a),

• communicated (with),

• and destructicated

• at run time.

• Lather, rinse, repeat until the owner ends.

Dynamic Lifetimes• Object provides service to one owner.

• Object life is briefer than its owner.

• Object’s lifespan matches its owner.

• Good candidate for static composition.

• Object provides service to 2+ subscribers.

• Good candidate for breadboarding or publish/subscribe.

Reflex Embraces,

Extends and Consumes Both

Examples are next.

ReflexHow to Use It!

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

Anonymous Callbacks

Ye Olde Coderefuse Reflex::Interval;

• my $i_one = Reflex::Interval->new(• interval => 1,

on_tick => sub { print "tick one...\n" },);

my $i_two = Reflex::Interval->new( interval => 0.5, on_tick => sub { print "tick two...\n" },);

Reflex->run_all();

Ye Olde Coderefuse Reflex::Interval;

my $i_one = Reflex::Interval->new( interval => 1,

• on_tick => sub { print "tick one...\n" },);

my $i_two = Reflex::Interval->new( interval => 0.5, on_tick => sub { print "tick two...\n" },);

Reflex->run_all();

Ye Olde Coderefuse Reflex::Interval;

my $i_one = Reflex::Interval->new( interval => 1, on_tick => sub { print "tick one...\n" },);

• my $i_two = Reflex::Interval->new(• interval => 0.5,

on_tick => sub { print "tick two...\n" },);

Reflex->run_all();

Ye Olde Coderefuse Reflex::Interval;

my $i_one = Reflex::Interval->new( interval => 1, on_tick => sub { print "tick one...\n" },);

my $i_two = Reflex::Interval->new( interval => 0.5,

• on_tick => sub { print "TICK TWO!!!\n" },);

Reflex->run_all();

tick one...TICK TWO!!!TICK TWO!!!tick one...TICK TWO!!!TICK TWO!!!tick one...TICK TWO!!!TICK TWO!!!^C

Ye Olde Coderef

Ye Olde Coderef - The Good

• Quick and dead simple to use.

• Convenient and fast for small things.

• Parsimonious use of memory.

Ye Olde Coderef - The Bad

• Circular references and memory leaks—unless you explicitly manage memory.

• Anti-pattern if done solely for speed...

• Implementation detail wags the dog.

• Giving up OO benefits for speed.

Ye Olde Coderef - The Ugly# A twisty maze of coderefs, all alike.

Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub { Watcher( sub {

Method Callbacks

Method Callbacks{

• package TickingThing;• use Moose; extends "Reflex::Base";

use Reflex::Interval;

has ticker => ( isa => "Reflex::Interval", is => "rw", default => sub { my $self = shift(); Reflex::Interval->new( interval => 1, on_tick => [ $self, "callback" ], ) }, );

sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

Method Callbacks{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

• has ticker => (• isa => "Reflex::Interval", is => "rw",

default => sub { my $self = shift(); Reflex::Interval->new( interval => 1, on_tick => [ $self, "callback" ], ) }, );

sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

has ticker => ( isa => "Reflex::Interval", is => "rw", default => sub { my $self = shift(); Reflex::Interval->new(

• interval => 1, on_tick => [ $self, "callback" ], ) }, );

sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

Method Callbacks

{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

has ticker => ( isa => "Reflex::Interval", is => "rw", default => sub { my $self = shift(); Reflex::Interval->new(

• interval => 1, on_tick => [ $self, "callback" ], ) }, );

• sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

Method Callbacks

method got tick...method got tick...method got tick...method got tick...method got tick...method got tick...method got tick...method got tick...method got tick...method got tick...^C

Method Callbacks

Methods – The Costs

• Verbose syntax.

• Perl OO is slower than code references and closures.

• Perl OO requires memory.

• Moose uses memory, too.

Methods – The Benefits

• Syntax gets sweeter.

• Object oriented design is cleaner and more extensible.

• No twisty maze of nested code references, all different.

• It’s all “standard” Perl and/or Moose.

Methods – The Future

• Avoiding flexibility by design is a dead end.

• Speed and size improve over time.

• Perl may get its own MOP.

• Moose and Moose-alikes may converge as Perl standardizes common features.

“But callbacks suck!” you say?

Promises

“an object that acts as a proxy for a result that is initially not known, usually because the computation of its value has not yet completed.”

— Wikipedia

What’s a Promise?

What’s a Promise?

Blah, blah, blah.

Promises• Asynchronous event generator.

• Create it.

• Do other stuff while it’s working.

• Pick up the next result later.

• Blocks or returns “incomplete” if not done.

• Implementation decides which.

• Future release may let the caller decide.

use Reflex::Interval;

• my $one = Reflex::Interval->new(• interval => 1• );

my $two = Reflex::Interval->new( interval => 2);

Timer Promise (1 of 2)

use Reflex::Interval;

my $one = Reflex::Interval->new( interval => 1);

• my $two = Reflex::Interval->new(• interval => 2• );

Timer Promise (1 of 2)

print "Before : ", time(), "\n";

• my $event = $two->next();• print "After two: ", time(), "\n";

$event = $one->next();print "After one: ", time(), "\n";

Timer Promise (2 of 2)

print "Before : ", time(), "\n";

my $event = $two->next();print "After two: ", time(), "\n";

• $event = $one->next();• print "After one: ", time(), "\n";

Timer Promise (2 of 2)

% perl promises.pl • Before : 1295045065• After two: 1295045067

After one: 1295045067

Eventy Timer Promise

Blocked 2 seconds.

% perl promises.pl Before : 1295045065

• After two: 1295045067• After one: 1295045067

Eventy Timer Promise

Instant result.

When to Avoid! Shun!

• Only use Reflex’s promises for asynchronous tasks that may need to wait.

• Synchronous generators and iterators are more efficient for computation.

“We were somewhere around Asheville in the

heart of the Blue Ridge Mountains when the Moose began to

take hold.”

Subclassing

Simpler Method Callbacks

Method Callbacks{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

• has ticker => (• isa => "Reflex::Interval", is => "rw",

default => sub { my $self = shift(); Reflex::Interval->new( interval => 1, on_tick => [ $self, "callback" ], ) }, );

sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

Method Callbacks{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

has ticker => ( isa => "Reflex::Interval", is => "rw", default => sub { my $self = shift(); Reflex::Interval->new(

• interval => 1, on_tick => [ $self, "callback" ], ) }, );

• sub callback { print "method got tick...\n" }}

Thing->new()->run_all();

Method Callbacks{ package TickingThing; use Moose; extends "Reflex::Base"; use Reflex::Interval;

has ticker => ( isa => "Reflex::Interval", is => "rw", default => sub { my $self = shift(); Reflex::Interval->new( interval => 1, on_tick => [ $self, "callback" ], ) }, );

sub callback { print "method got tick...\n" }}

• Thing->new()->run_all();

Subclassed Interval

{• package TickingThing;

use Moose;• extends "Reflex::Interval";

before on_tick => sub { print "customized tick...\n" };}

TickingThing->new( interval => 1 )->run_all();

Subclassed Interval

{ package TickingThing; use Moose; extends "Reflex::Interval";

• before on_tick => sub {• print "customized tick...\n"

};}

TickingThing->new( interval => 1 )->run_all();

Subclassed Interval

{ package TickingThing; use Moose; extends "Reflex::Interval";

before on_tick => sub { print "customized tick...\n" };}

• TickingThing->new( interval => 1 )->run_all();

Roles

Roles

• They’re sticky.

• They’re delicious.

• They’re high in carbohydrate calories.

• They may contain bacon.

Reflex Roles

• Eventy features are implemented as roles.

• Consume them when appropriate.

• Each role has a corresponding class.

• Reflex::Interval is Reflex::Role::Interval.

Reflex::Interval (1 of 3)

package Reflex::Interval;use Moose; extends "Reflex::Base";

• has interval => ( isa => "Num", is => "rw");

• has auto_repeat => ( isa => "Bool", is => "ro", default => 1);

• has auto_start => ( isa => "Bool", is => "ro", default => 1);

Reflex::Interval (2 of 3)

with "Reflex::Role::Interval" => {• att_interval => "interval",• att_auto_start => "auto_start",• att_auto_repeat => "auto_repeat",

cb_tick => "on_tick", method_start => "start", method_stop => "stop", method_repeat => "repeat",};

sub on_tick { my ($self, $args) = @_; $self->emit( event => "tick", args => $args );}

Reflex::Interval (2 of 3)

with "Reflex::Role::Interval" => { att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat",

• cb_tick => "on_tick", method_start => "start", method_stop => "stop", method_repeat => "repeat",};

• sub on_tick { my ($self, $args) = @_;

• $self->emit(• event => "tick", args => $args

);}

Reflex::Interval (2 of 3)

with "Reflex::Role::Interval" => { att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat", cb_tick => "on_tick",

• method_start => "start",• method_stop => "stop",• method_repeat => "repeat",

};

sub on_tick { my ($self, $args) = @_; $self->emit( event => "tick", args => $args );}

1;Reflex::Interval (3 of 3)

Parameterized Roles

• Reflex uses role parameters to wire together code.

• MooseX::Role:: Parameterized rocks for this.

Three Kinds of Role Parameters

Attribute Parameters

• Name attributes in the consumer that control role behavior.

• Begin with “att_”.

Attribute Parameterspackage Reflex::Interval;use Moose;

• has interval => ( isa => "Num", ... );• has auto_start => ( isa => "Bool", ... );

...;

with "Reflex::Role::Interval" => { att_interval => "interval", att_auto_start => "auto_start", ...,};

Attribute Parameterspackage Reflex::Interval;use Moose;

has interval => ( isa => "Num", ... );has auto_start => ( isa => "Bool", ... );...;

with "Reflex::Role::Interval" => {• att_interval => "interval",• att_auto_start => "auto_start",

...,};

Callback Parameters

• Name consumer methods to call back when things happen.

• Begin with “cb_”.

• These callbacks are simple, synchronous method calls.

Callback Parameterspackage Reflex::Interval;use Moose;...;

with "Reflex::Role::Interval" => {• cb_tick => "on_tick",

...,};

• sub on_tick { my ($self, $args_hash) = @_; ...;}

Method Parameters

• Roles may implement public API methods.

• Classes get to decide what they’re called.

• Begin with “method_”.

Method Parameters{ package Reflex::Interval; use Moose; extends "Reflex::Base";

with "Reflex::Role::Interval" => { ...,

• method_start => "start",• method_stop => "stop",

};}

my $interval = Reflex::Interval->new();• $interval->stop();• $interval->start();

Lots of Role

Parameters

Awesome but

tedious to configure.

Dynamic Defaults

• Each role designates a primary attribute parameter.

• Other parameter default values are based on the primary parameter’s value.

• Avoids namespace clashes as an extension of basic OO.

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "watchdog", ...,}

Role Parameter Default Name

method_start start_watchdog()

method_stop stop_watchdog()

cb_tick on_watchdog_tick()

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "log_rotation", ...,}

Role Parameter Default Name

method_start start_log_rotation()

method_stop stop_log_rotation()

cb_tick on_log_rotation_tick()

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "interval",• att_auto_start => "auto_start",• att_auto_repeat => "auto_repeat",• cb_tick => "on_tick",• method_start => "start",• method_stop => "stop",• method_repeat => "repeat",

};

Redundancy is a special case.It overrides generally useful defaults.

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat",

• cb_tick => "on_tick", method_start => "start", method_stop => "stop", method_repeat => "repeat",};

Calls $self->on_tick()... not $self->on_interval_tick()

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat", cb_tick => "on_tick",

• method_start => "start", method_stop => "stop", method_repeat => "repeat",};

Creates $interval->start()... not $interval->start_interval()

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat", cb_tick => "on_tick", method_start => "start",

• method_stop => "stop", method_repeat => "repeat",};

Creates $interval->stop()... not $interval->stop_interval()

Primary Attributewith "Reflex::Role::Interval" => {

• att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat", cb_tick => "on_tick", method_start => "start", method_stop => "stop",

• method_repeat => "repeat",};

Etc.

Other Moose Magic

Expose Inner Workings

Expose Inner Workings{

• package AnotherTickingThing;• use Moose; extends "TickingThing";

has "+ticker" => ( handles => [ "interval" ], );}

my $thing = AnotherTickingThing->new();$thing->interval(0.1);$thing->run_all();

Expose Inner Workings{ package AnotherTickingThing; use Moose; extends "TickingThing";

• has "+ticker" => (• handles => [ "interval" ],• );

}

my $thing = AnotherTickingThing->new();$thing->interval(0.1);$thing->run_all();

Expose Inner Workings{ package AnotherTickingThing; use Moose; extends "TickingThing";

has "+ticker" => ( handles => [ "interval" ], );}

my $thing = AnotherTickingThing->new();• $thing->interval(0.1);

$thing->run_all();

Replace Inner Workings

Replace Inner Workings

my $thing = TickingThing->new();

• $thing->ticker(• Reflex::Interval->new(• interval => 0.125,

on_tick => [ $thing, "callback" ], ));

$thing->run_all();

• my $thing = TickingThing->new( ticker => Reflex::Interval->new( interval => 0.125,

• on_tick => [ $thing, "callback" ], ));

Replace Inner Workings

Can’t use $thing like this.It must be declared before it can be used.

Two statements.Reference to $thing held inside $thing.

Replace Inner Workings

• my $thing;• $thing = TickingThing->new(

ticker => Reflex::Interval->new( interval => 0.125,

• on_tick => [ $thing, "callback" ], ));

• my $thing = TickingThing->new();

• $thing->ticker( Reflex::Interval->new( interval => 0.125,

• on_tick => [ $thing, "callback" ], ));

Dynamically replace it later.Reference to $thing held inside $thing.

Replace Inner Workings

my $thing = TickingThing->new();

$thing->ticker( Reflex::Interval->new( interval => 0.125,

• on_tick => [ $thing, "callback" ], ));

Either way, Reflex automatically weakens the inner reference for you.

Replace Inner Workings

Override Attributes

Override Attributes

{• package FasterInterval;• use Moose; extends "Reflex::Interval";

has "+interval" => ( default => 0.5, );}

FasterInterval->new()->run_all();

Override Attributes

{ package FasterInterval; use Moose; extends "Reflex::Interval";

• has "+interval" => (• default => 0.5,

);}

FasterInterval->new()->run_all();

Override Attributes

{ package FasterInterval; use Moose; extends "Reflex::Interval";

has "+interval" => ( default => 0.5, );}

• FasterInterval->new()->run_all();

Whatever Objects Can Do

What Can’t Objects Do?

ReflexHow does it work?

Rocco Caputo – @rcaputoYAPC::NA

Tuesday, 28 June 2011Around Teatime

Static Reflex=

Moose

Dynamic Reflex

=Emit & Watch

Crossing the Barrier Between Static & Dynamic

Interaction

Static to Dynamic

• Classes are built using static roles.

• Classes implement additional features.

• Callbacks within a class are synchronous.

• Classes emit dynamic messages.

• Dynamic object interaction is based on watching for those messages.

Default Callbackwith "Reflex::Role::Interval" => { att_interval => "interval", att_auto_start => "auto_start", att_auto_repeat => "auto_repeat",

• cb_tick => "on_tick", method_start => "start", method_stop => "stop", method_repeat => "repeat",};

• sub on_tick { my ($self, $args) = @_;

• $self->emit(• event => "tick", args => $args

);}

Dynamic back to Static?

Just Call Stuff, Okay?

Trade Offs

• Dynamic object interaction is richer, more fun, and often necessary.

• Beware of using dynamic messages solely “for fun’s sake”.

• Static callbacks are more efficient.

Emitting an Event• package Moosian; use Moose;• extends "Reflex::Base";

has name => ( is => "ro", isa => "Str" );

sub yip { my ($self, $args) = @_; print( $self->name(), " says: Yip-yip-yip-yip..", " uh-huh uh-huh..\n" ); $self->emit( event => "yipped" );}

1;

Emitting an Eventpackage Moosian; use Moose;extends "Reflex::Base";

has name => ( is => "ro", isa => "Str" );

• sub yip { my ($self, $args) = @_;

• print(• $self->name(),• " says: Yip-yip-yip-yip..",• " uh-huh uh-huh..\n"• );

$self->emit( event => "yipped" );}

1;

Emitting an Eventpackage Moosian; use Moose;extends "Reflex::Base";

has name => ( is => "ro", isa => "Str" );

sub yip { my ($self, $args) = @_; print( $self->name(), " says: Yip-yip-yip-yip..", " uh-huh uh-huh..\n" );

• $self->emit( event => "yipped" );}

1;

Emitting Events

• Objects emit() events as part of their public interfaces.

• Events have no explicit destination.

• It’s up to users to watch() for events.

Watching Events

• my $bob = Moosian->new( name => "Bob" );my $joe = Moosian->new( name => "Joe" );

• $bob->watch( $joe, "yipped", "yip" );$joe->watch( $bob, "yipped", "yip" );

$bob->yip();

Reflex->run_all();

Watching Events

my $bob = Moosian->new( name => "Bob" );• my $joe = Moosian->new( name => "Joe" );

$bob->watch( $joe, "yipped", "yip" );• $joe->watch( $bob, "yipped", "yip" );

$bob->yip();

Reflex->run_all();

Watching Events

my $bob = Moosian->new( name => "Bob" );my $joe = Moosian->new( name => "Joe" );

$bob->watch( $joe, "yipped", "yip" );$joe->watch( $bob, "yipped", "yip" );

• $bob->yip();

• Reflex->run_all();

Moosian Dialog

Bob says: Yip-yip-yip-yip... uh-huh uh-huh..Joe says: Yip-yip-yip-yip... uh-huh uh-huh..Bob says: Yip-yip-yip-yip... uh-huh uh-huh..Joe says: Yip-yip-yip-yip... uh-huh uh-huh..Bob says: Yip-yip-yip-yip... uh-huh uh-huh..Joe says: Yip-yip-yip-yip... uh-huh uh-huh..Bob says: Yip-yip-yip-yip... uh-huh uh-huh..Joe says: Yip-yip-yip-yip... uh-huh uh-huh..Bob says: Yip-yip-yip-yip... uh-huh uh-huh..Joe says: Yip-yip-yip-yip... uh-huh uh-huh..^C

Infinite Recursion OK

TIME RSS COMMAND• 1:16.60 17940 perl moosians.pl

TIME RSS COMMAND 2:37.94 17940 perl moosians.pl

TIME RSS COMMAND 3:05.86 17940 perl moosians.pl

TIME RSS COMMAND 3:30.69 17940 perl moosians.pl

Infinite Recursion OK

TIME RSS COMMAND 1:16.60 17940 perl moosians.pl

TIME RSS COMMAND• 2:37.94 17940 perl moosians.pl

TIME RSS COMMAND 3:05.86 17940 perl moosians.pl

TIME RSS COMMAND 3:30.69 17940 perl moosians.pl

Infinite Recursion OK

TIME RSS COMMAND 1:16.60 17940 perl moosians.pl

TIME RSS COMMAND 2:37.94 17940 perl moosians.pl

TIME RSS COMMAND• 3:05.86 17940 perl moosians.pl

TIME RSS COMMAND 3:30.69 17940 perl moosians.pl

Infinite Recursion OK

TIME RSS COMMAND 1:16.60 17940 perl moosians.pl

TIME RSS COMMAND 2:37.94 17940 perl moosians.pl

TIME RSS COMMAND 3:05.86 17940 perl moosians.pl

TIME RSS COMMAND• 3:30.69 17940 perl moosians.pl

Simplified Hierarchical Watching

Hierarchical Watching?• Most program

structure is hierarchical.

• Trees of objects that use other objects.

• Parent objects often need results from children.

Moose Traits Rock

Watched Attributes

Callbacks Discovered by

Name

• use Reflex::Trait::Watched qw(watches);

• watches clock => ( isa => "Reflex::Interval", setup => sub { Reflex::Interval->new(interval => 1) },);

sub on_clock_tick { print "tick...\n" }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

watches clock => ( isa => "Reflex::Interval", setup => sub { Reflex::Interval->new(interval => 1) },);

• sub on_clock_tick { print "tick...\n" }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

watches clock => ( isa => "Reflex::Interval", setup => sub { Reflex::Interval->new(interval => 1) },);

• sub on_clock_tick { print "tick...\n" }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

• watches clock => ( isa => "Reflex::Interval", setup => sub { Reflex::Interval->new(interval => 1) },);

• sub on_clock_tick { print "tick...\n" }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

watches clock => (• isa => "Reflex::Interval",

setup => sub { Reflex::Interval->new(interval => 1) },);

• sub on_clock_tick { print "tick...\n" }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

• watches penguin => (• isa => "Reflex::Bomb",

setup => sub { ... },);

sub on_penguin_tick { ... }sub on_penguin_stop { ... }sub on_penguin_explode { ... }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

watches penguin => ( isa => "Reflex::Bomb", setup => sub { ... },);

• sub on_penguin_tick { ... }• sub on_penguin_stop { ... }• sub on_penguin_explode { ... }

Watched Attributes

use Reflex::Trait::Watched qw(watches);

• watches watchdog => ( ... Interval ... );• watches log_mark => ( ... Interval ... );

• sub on_watchdog_tick { ... }• sub on_log_mark_tick { ... }

Watched Attributes

Reflex Role Composition

Two-Way Pipe Driver

• Bidirectionally stream data between two file handles.

• Useful for proxies.

Two File Handles• package Proxy;

use Moose;extends "Reflex::Base";

• has client => (• isa => "FileHandle",

is => "rw", required => 1 );

• has server => (• isa => "FileHandle",

is => "rw", required => 1 );

• has active => (• isa => "Bool",

is => "ro", default => 1 );

Reduced for Example

• use Reflex::Callbacks "make_null_handler";

• make_null_handler("on_client_closed");• make_null_handler("on_client_error");

• make_null_handler("on_server_closed");• make_null_handler("on_server_error");

From Client to Server

• with "Reflex::Role::Streaming" => { att_active => "active",

• att_handle => "client",};

sub on_client_data { my ($self, $arg) = @_; $self->put_server($arg->{data});}

From Client to Server

with "Reflex::Role::Streaming" => { att_active => "active", att_handle => "client",};

• sub on_client_data { my ($self, $arg) = @_;

• $self->put_server($arg->{data});}

From Server to Client

• with "Reflex::Role::Streaming" => { att_active => "active",

• att_handle => "server",};

sub on_server_data { my ($self, $arg) = @_; $self->put_client($arg->{data});}

From Server to Client

with "Reflex::Role::Streaming" => { att_active => "active", att_handle => "server",};

• sub on_server_data { my ($self, $arg) = @_;

• $self->put_client($arg->{data});}

1;We’re “Done”

Quote-Done-Unquote

• Not handling EOF (cb_closed).

• Not handling errors (cb_error).

• We’ll probably need separate “active” flags for client and server later.

• Flow-control for data rate mismatches?

• Etc.

Usage

# Assume we already have the sockets.

• my $p = Proxy->new(• client => $client_socket,• server => $server_socket,

);

# Do something else while it runs.

Simple?

I Wrote What?

on_client_dataon_client_closedon_client_errorput_clientstop_clienton_server_dataon_server_closedon_server_errorput_serverstop_server

clientserveractive

Proxy

att_handleatt_activecb_datacb_closedcb_errormethod_putmethod_stop

Reflex::Role::Streaming

cb_readymethod_pausemethod_resumemethod_startmethod_stop

att_handleatt_active

Reflex::Role::Writable

cb_errormethod_putmethod_flush

att_handleReflex::Role::Writing

cb_readymethod_pausemethod_resumemethod_stop

att_handleatt_active

Reflex::Role::Readable

cb_closedcb_datacb_errormethod_read

att_handleReflex::Role::Reading

att_handleatt_activecb_datacb_closedcb_errormethod_putmethod_stop

Reflex::Role::Streaming

cb_readymethod_pausemethod_resumemethod_startmethod_stop

att_handleatt_active

Reflex::Role::Writablecb_errormethod_putmethod_flush

att_handleReflex::Role::Writing

cb_readymethod_pausemethod_resumemethod_stop

att_handleatt_active

Reflex::Role::Readable

cb_closedcb_datacb_errormethod_read

att_handleReflex::Role::Reading

Reflex::Role::StreamingReflex Role The ability to....

Reading ... read data from a non-blocking file handle.

Readable ... watch for data arriving on a file handle.

Writing ... buffer and/or write data to a NB file handle.

Writable ... watch a file handle for ability to write data.

Relax–It’s Just the Class

• That’s the Proxy class.

• All instances will share the same code.

Overkill? Dial it Back!

Roles let programs pick and mix what

they need.

Reflex::Role::InStreaming

att_handleatt_activecb_datacb_closedcb_errormethod_stop

Reflex::Role::InStreaming

cb_readymethod_pausemethod_resumemethod_stop

att_handleatt_active

Reflex::Role::Readable

cb_closedcb_datacb_errormethod_read

att_handleReflex::Role::Reading

Reflex::Role::OutStreaming

att_handleatt_activecb_datacb_closedcb_errormethod_putmethod_stop

Reflex::Role::OutStreaming

cb_readymethod_pausemethod_resumemethod_startmethod_stop

att_handleatt_active

Reflex::Role::Writable

cb_errormethod_putmethod_flush

att_handleReflex::Role::Writing

Dynamic Fun

SmallTalk-Like Messaging

Auto-Emit Messages When

Attributes Change

• package EmittingCounter;

• use Reflex::Trait::EmitsOnChange qw(emits);

emits count => ( isa => "Int", default => 0);

sub something_happens { my $self = shift; $self->count($self->count() + 1);}

SmallTalk Messaging

package EmittingCounter;

use Reflex::Trait::EmitsOnChange qw(emits);

• emits count => ( isa => "Int", default => 0);

sub something_happens { my $self = shift;

• $self->count($self->count() + 1);}

SmallTalk Messaging

Now Watch It• use EmittingCounter;

use Reflex::Trait::Watched qw(watches);

• watches counter => (• isa => "EmittingCounter",

setup => sub { EmittingCounter-> new() },);

sub on_counter_count { my ($self, $args) = @_; print "counter reached $args->{value}\n";}

Now Watch Ituse EmittingCounter;use Reflex::Trait::Watched qw(watches);

watches counter => ( isa => "EmittingCounter", setup => sub { EmittingCounter-> new() },);

• sub on_counter_count { my ($self, $args) = @_;

• print "counter reached $args->{value}\n";}

Self-Managed

Collections

Reflex::Collection

• Manages objects that do Reflex::Role::Collectible.

• Collectible objects are automatically cleaned up when they stop.

• Great for create-and-forget things.

Echo Server (1 of 1)

{• package TcpEchoServer; use Moose;• extends "Reflex::Acceptor"; use EchoStream;

use Reflex::Collection qw(has_many);

has_many clients => ( handles => { remember_client => "remember" } );

sub on_accept { my ($self, $args) = @_; $self->remember_client( EchoStream->new( handle => $args->{socket} ) ); }}

Echo Server (1 of 1)

{ package TcpEchoServer; use Moose;

• extends "Reflex::Acceptor"; use EchoStream; use Reflex::Collection qw(has_many);

has_many clients => ( handles => { remember_client => "remember" } );

sub on_accept { my ($self, $args) = @_; $self->remember_client( EchoStream->new( handle => $args->{socket} ) ); }}

Echo Server (1 of 1)

{ package TcpEchoServer; use Moose; extends "Reflex::Acceptor"; use EchoStream;

• use Reflex::Collection qw(has_many);

has_many clients => ( handles => { remember_client => "remember" } );

sub on_accept { my ($self, $args) = @_; $self->remember_client( EchoStream->new( handle => $args->{socket} ) ); }}

Echo Server (1 of 1)

{ package TcpEchoServer; use Moose; extends "Reflex::Acceptor"; use EchoStream; use Reflex::Collection qw(has_many);

• has_many clients => (• handles => {• remember_client => "remember"

} );

sub on_accept { my ($self, $args) = @_; $self->remember_client( EchoStream->new( handle => $args->{socket} ) ); }}

{ package TcpEchoServer; use Moose; extends "Reflex::Acceptor"; use EchoStream; use Reflex::Collection qw(has_many);

has_many clients => ( handles => { remember_client => "remember" } );

• sub on_accept { my ($self, $args) = @_;

• $self->remember_client(• EchoStream->new( handle => $args->{socket} )

); }}

Echo Server (1 of 1)

EchoStream (1 of 1)

• package EchoStream;use Moose;

• extends "Reflex::Stream";

sub on_data { my ($self, $args) = @_; $self->put($args->{data});}

1;

EchoStream (1 of 1)

package EchoStream;use Moose;extends "Reflex::Stream";

• sub on_data { my ($self, $args) = @_;

• $self->put($args->{data});}

1;

POE Compatibility

Benefits of POE

• Mature and stable.

• Use any event loop you want.

• Hundreds of existing modules.

• Thousands of users.

• And you.

• Don’t rewrite everything at once.

POE Compatibility

• Migrate incrementally.

• Reflex can talk to POE modules.

• POE modules can talk to Reflex objects.

• “Separate but equal” is not enough.

• Static Reflex is faster than POE message passing.

• Reflex eg directory contains examples.

“But is Reflex Ready?”

40% Complete!

• Large swathes of design are stable.

• Documentation!

• ... which I broke preparing for this talk.

• Bugs!

• ... which I added preparing for this talk.

• Roadmap documented in the repository.

Help Make It Better

• http://github.com/rcaputo/reflex

• See the roadmap.

• #reflex on irc.perl.org

• poe-subscribe@perl.org

• Hackathon, BOF or hallway track.

• Use it, and complain... to me.

• Influence the project while it’s still plastic.

Contribute to a Project• Nick Perez’s Reflex-based psgi server.

• Reflexive::Role::CollectiveInteract with a collection of reflexive objects.

• Reflexive::Role::DataMoverMove data between two streams.

• Reflexive::Role::TCPServerBecome a fully featured TCP server.

• Reflexive::Stream::FilteringApply POE filters to Reflex streams.

• (Your Project Here)

Thank you!

WebliographyDrawing of Edgar Allan Poe.

“A Softer World” comic.

Wizard Moose

Edgar Allan Bro

Universum

Tiled Angry Moose

Accidental Goatse (Unused)

Self-Herding Cat

ORM Diagram

POE's users are outstanding in their fields.

Moose Antlers

Promise Ring

The Watchers

A Fighter Jet Made of Biceps