• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Reflex - How Does It Work? (extended dance remix)
 

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

on

  • 3,335 views

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....

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.

Statistics

Views

Total Views
3,335
Views on SlideShare
3,327
Embed Views
8

Actions

Likes
2
Downloads
20
Comments
0

4 Embeds 8

http://www.linkedin.com 3
http://www.slideshare.net 2
http://twitter.com 2
http://paper.li 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

    • ReflexHow does it work? Rocco Caputo – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around Teatime
    • Feedback, plx.
    • This talkdescribes theGithub Version
    • 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
    • EdgarAllan Poe
    • Anne DecaturDanielewski
    • The Other Committers• Adam Kennedy • Jonathan Steinert• Benjamin Smith • Larwan Berke• Casey West • Martijn van Beers• Chris Fedde • Matt Cashner• Chris Williams • Matt Sickler• David Davis • Perl Whore• David Webb • Philip Gwyn• Hinrik Örn Sigurðsson • Tom Feist• jmadler • 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 • DavidGolden • David Snopek • Denis Pokataev • Dmitry Karasik • dmitry kim •Eriam Schaffter • Eric Waters • Erick Calder • George Nistorica • GregFast • Guillermo Roditi • Hans Dieter Pearcey • Ivan B. Serezhkin • J. J.Merelo Guervos • Jan Henning Thorsen • Jason McManus • Jeff Bisbee • JeffGoff • 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 • MatthewO’Connor • Michael Ching • Michael R. Davis • Michael Schilli • MikeFletcher • Mike Schroeder • Mischa Spiegelmock • MOCK • MSERGEANT •Nicholas Perez • Olivier ‘dolmen’ Mengue • Paul David Tinsley • PaulDriver • Paul Evans • Paul G Webster • Paul Visscher • Pavel Boldin •Pedro Melo • Peter Guzis • Przemyslaw Iskra • Rafael Kitover • RichardClamp • Rob Bloodgood • Rob Partington • Robert ‘phaylon’ Sedlacek •Sawyer X • Scott Beck • Scott McCoy • Sean Egan • Sebastien Aperghis-Tramoni • Sergey Kotenko • Sergey Skvortsov • Sjors Gielen • StephenAdkins • 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
    • The UsersEOVERFLOW
    • Okay, me too.
    • Digression:See Digression
    • ReflexWhat Is It?Rocco Caputo – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around Teatime
    • ReflexWhat Isn’t It?Rocco Caputo – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around 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.
    • CPANalready has too many event loops.
    • Event loopsare the means, not the ends.
    • Reflex iseventy withoutso much loopy.
    • Nor is Reflex an object system.
    • CPANalready has too many object systems.
    • Reflex uses Moose
    • But Why?!“I am disappointed that after all thistime we have no consensus on howto say in Perl ‘Class X has attributeY’ when so many other languageshave solutions that have freed theirusers’ minds up to move on tohigher-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 – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around Teatime
    • The ORM ofEvent Loops!!
    • Marketingbullshit aside...
    • ReactiveProgram Building Blocks
    • Building BlocksProvidedby Moose
    • Plus a Reactorprovided by Your Favorite Event Loop
    • Invisible Event Loop
    • Like ORMs hide SQL ORM behind objects... DB
    • Reflexhides event loops Reflex behind The Events objects... Can
    • Reflex isModern 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 eventyinteraction.
    • Rule 34 for PerlIf you can thinkof it, CPAN hasa module for it.
    • TIMTOWTDIIf you can thinkof it, CPAN has2+ incompatiblemodules for it...
    • TIMTOWTDI ... and someday you’ll need touse 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 ½ RulesMake it Work
    • ⁓1⁓Objects must not dictate callback mechanisms.
    • ⁓ 1.5 ⁓ Users define how theyreceive callbacks.
    • ⁓2⁓The base systemmust support alldesired callback types.
    • ⁓3⁓ Reflex must dojust enough work to be correct.
    • Reflex unifieseventy program composition.
    • “How EventyPrograms arePut 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 andConsumes Both
    • Examples are next.
    • ReflexHow to Use It! Rocco Caputo – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around Teatime
    • Anonymous Callbacks
    • Ye Olde Coderef use 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 Coderef use 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 Coderef use 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 Coderef use 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 Codereftick one...TICK TWO!!!TICK TWO!!!tick one...TICK TWO!!!TICK TWO!!!tick one...TICK TWO!!!TICK TWO!!!^C
    • 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 {
    • MethodCallbacks
    • 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();
    • 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 Callbacksmethod 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
    • 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 callbackssuck!” you say?
    • Promises
    • What’s a Promise?“an object that acts as a proxyfor a result that is initially notknown, usually because thecomputation of its value has notyet completed.” — Wikipedia
    • 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.
    • 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) use Reflex::Interval; my $one = Reflex::Interval->new( interval => 1 );• my $two = Reflex::Interval->new(• interval => 2• );
    • 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) print "Before : ", time(), "n"; my $event = $two->next(); print "After two: ", time(), "n";• $event = $one->next();• print "After one: ", time(), "n";
    • Eventy Timer Promise % perl promises.pl• Before : 1295045065 Blocked 2 seconds.• After two: 1295045067 After one: 1295045067
    • Eventy Timer Promise % perl promises.pl Before : 1295045065• After two: 1295045067 Instant result.• After one: 1295045067
    • 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 somewherearound Asheville in the heart of the BlueRidge 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 ); }
    • Reflex::Interval (3 of 3) 1;
    • Parameterized Roles• Reflex uses role parameters to wire together code.• MooseX::Role:: Parameterized rocks for this.
    • Three Kinds ofRole Parameters
    • Attribute Parameters• Name attributes in the consumer that control role behavior.• Begin with “att_”.
    • Attribute Parameters package 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 Parameters package 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 Parameters package 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 RoleParameters
    • Awesome buttedious toconfigure.
    • 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 Attribute with "Reflex::Role::Interval" => {• att_interval => "watchdog", ..., }Role Parameter Default Name method_start start_watchdog() method_stop stop_watchdog() cb_tick on_watchdog_tick()
    • Primary Attribute with "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 Attribute 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", }; Redundancy is a special case. It overrides generally useful defaults.
    • Primary Attribute 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", };Calls $self->on_tick() ... not $self->on_interval_tick()
    • Primary Attribute 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", };Creates $interval->start() ... not $interval->start_interval()
    • Primary Attribute 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", };Creates $interval->stop() ... not $interval->stop_interval()
    • Primary Attribute 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", }; Etc.
    • OtherMooseMagic
    • 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();
    • Replace Inner Workings• my $thing = TickingThing->new( ticker => Reflex::Interval->new( interval => 0.125,• on_tick => [ $thing, "callback" ], ) ); Can’t use $thing like this. It must be declared before it can be used.
    • Replace Inner Workings• my $thing;• $thing = TickingThing->new( ticker => Reflex::Interval->new( interval => 0.125,• on_tick => [ $thing, "callback" ], ) ); Two statements. 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" ], ) ); 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.
    • OverrideAttributes
    • 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();
    • WhateverObjectsCan Do
    • What Can’tObjects Do? ☺
    • ReflexHow does it work? Rocco Caputo – @rcaputo YAPC::NA Tuesday, 28 June 2011 Around Teatime
    • Static Reflex = Moose
    • Dynamic Reflex = Emit & Watch
    • Crossing theBarrier BetweenStatic & 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 Callback 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 ); }
    • Dynamic back to Static? Just CallStuff, 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 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 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 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 DialogBob 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
    • SimplifiedHierarchical 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
    • WatchedAttributes
    • CallbacksDiscovered by Name
    • 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 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 { ... }
    • Reflex RoleComposition
    • 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}); }
    • We’re “Done” 1;
    • 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? Reflex::Role::Writable att_handle Reflex::Role::Reading att_active att_handle cb_ready cb_closed method_pause cb_data method_resume cb_error method_start method_read Reflex::Role::ReadableReflex::Role::Writing method_stop att_handleatt_handle att_activecb_error cb_readymethod_put method_pausemethod_flush Proxy method_resume client method_stop server Reflex::Role::Streaming active Reflex::Role::Streaming att_handle on_client_data att_handle att_active on_client_closed att_active cb_data on_client_error cb_data cb_closed put_client cb_closed cb_error stop_client cb_error method_put on_server_data method_put method_stop on_server_closed method_stop on_server_errorReflex::Role::Readable put_serveratt_handle stop_server Reflex::Role::Writingatt_active att_handlecb_ready cb_errormethod_pause method_put Reflex::Role::Writablemethod_resume method_flush Reflex::Role::Reading att_handlemethod_stop att_handle att_active cb_closed cb_ready cb_data method_pause cb_error method_resume method_read method_start method_stop
    • Reflex::Role::StreamingReflex The ability to.... RoleReading ... 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 letprograms pickand mix what they need.
    • Reflex::Role::InStreaming Reflex::Role::InStreaming att_handle att_active cb_data cb_closed cb_error method_stop Reflex::Role::Readable Reflex::Role::Reading att_handle att_handle att_active cb_closed cb_ready cb_data method_pause cb_error method_resume method_read method_stop
    • Reflex::Role::OutStreaming Reflex::Role::OutStreaming att_handle att_active cb_data cb_closed cb_error method_put method_stop Reflex::Role::Writable att_handle Reflex::Role::Writing att_active att_handle cb_ready cb_error method_pause method_put method_resume method_flush method_start method_stop
    • Dynamic Fun
    • SmallTalk-Like Messaging
    • Auto-EmitMessages When Attributes Change
    • 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 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); }
    • 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 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"; }
    • Self- ManagedCollections
    • 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} ) ); } }
    • 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} ) ); } }
    • 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;
    • POECompatibility
    • 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::Collective Interact with a collection of reflexive objects.• Reflexive::Role::DataMover Move data between two streams.• Reflexive::Role::TCPServer Become a fully featured TCP server.• Reflexive::Stream::Filtering Apply POE filters to Reflex streams.• (Your Project Here)
    • Thank you!
    • WebliographyDrawing of Edgar Allan Self-Herding CatPoe. ORM Diagram“A Softer World” comic. POEs users areWizard Moose outstanding in their fields.Edgar Allan Bro Moose AntlersUniversum Promise RingTiled Angry Moose The WatchersAccidental Goatse A Fighter Jet Made of(Unused) Biceps