1 / 20

Closures for Fun and Profit

Closures for Fun and Profit. Being a Lesson in what Closures are And a Demonstration of some Cool Shit using them. Closures for Fun and Profit. To understand closures, first understand objects. An object is a blob of data with some code associated with it. package Number; sub new {

kelsie-love
Télécharger la présentation

Closures for Fun and Profit

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Closures for Fun and Profit Being a Lesson in what Closures are And a Demonstration of some Cool Shit using them

  2. Closures for Fun and Profit To understand closures, first understand objects An object is a blob of data with some code associated with it package Number; sub new { my($class, $value) = @_; bless { value => $value }, $class; } This is not an object sub get { my $self = shift(); return $self->{value}; } sub set { my $self = shift(); $self->{value} = shift(); } sub add { my $self = shift(); $self->set($self->get() + shift()); } sub subtract { my $self = shift(); $self->set($self->get() - shift()); }

  3. Closures for Fun and Profit use Number; my $foo = Number->new(42); This is an object

  4. Closures for Fun and Profit A closure is a blob of code with some data associated with it sub make_closure { my $data = shift; return sub { ... } } sub make_closure { my $data = shift; return sub { my $arg = shift; } } sub make_closure { my $data = shift; return sub { my $arg = shift; return $arg + $data; } } Subroutine gets a copy of the variable when it is created - the code has some data associated with it … even after make_closure exits! (and this is why I think “inside-out objects” are badly named)

  5. Closures for Fun and Profit So let’s use our closure … sub make_closure { my $data = shift; return sub { my $arg = shift; return $arg + $data; } } This is not a closure my $add_2 = make_closure(2); my $add_5 = make_closure(5); This is a closure my $four = $add_2->(2); my $fortytwo = $add_5->(37);

  6. Closures for Fun and Profit Wasn’t that exciting! Summary: An object is a relationship which lets you do things to data Access the code via the data A closure is a relationship which lets you do things with data Access the data via the code Computer Scientists may now leave the room

  7. Closures for Fun and Profit Lucius Annæus Seneca (4 BCE - 65 CE) world’s first software engineer The way is made long by explaining, short and efficient by example Longum iter est per præcepta, breve et efficax per exempla The Death of Seneca, by Peter Paul Rubens

  8. Closures for Fun: CPU::Emulator::Z80 A Z80 emulator written in perl On the CPAN Make your code faster by writing time-critical bits in assembler! Andy Armstrong’s fault

  9. Closures for Fun: CPU::Emulator::Z80 LD D, 0x12 LD E, 0x34 0x16 0x12 0x1E 0x34 0b00010110 0x12 0b00011110 0x34 _LD_r8_imm(…) LD HL, 0xBEEF LD DE, 0x1234 0x11 0x1234 0b00010001 0x1234 _LD_r16_imm(…)

  10. Closures for Fun: CPU::Emulator::Z80 Every register is an object CPU::Emulator::Z80::Register8 for 8-bit registers like D and E CPU::Emulator::Z80::Register16 for 16-bit registers like HL _LD_r8_imm calls a Register8’s set() method _LD_r16_imm calls a Register16’s set() method So what about DE? I need a Register16, and to update two Register8s

  11. Closures for Fun: CPU::Emulator::Z80 package CPU::Emulator::Z80::Register16; # called as …->new( set => sub { … }, get => … ) sub new { my $class = shift; bless {@_}, $class; } sub set { # called by, eg, _LD_r16_imm() my $self = shift; if(exists($self->{set})) { $self->{set}->(shift) } else { $self->{value} = shift() & 0xFFFF } } Optionally pass in subroutines to use in the get()/set() method, which are responsible for accessing the real registers

  12. Closures for Fun: CPU::Emulator::Z80 package CPU::Emulator::Z80; … my $self = bless … # create the CPU my $register_DE = CPU::Emulator::Z80::Register16->new( set => sub { my $value = shift; $self->register(‘D’)->set(($value & 0xFF00) >> 8); $self->register(‘E’)->set($value & 0xFF); } ); Anonymous subroutine “closes over” $self Even when called from deep inside another object, $self still points back at the CPU object

  13. Closures for Fun: CPU::Emulator::Z80 my $register_BC = CPU::Emulator::Z80::Register16->new( set => sub { my $value = shift; $self->register(‘B’)->set(($value & 0xFE00) >> 8); $self->register(‘C’)->set($value & 0xFF); } ); my $register_DE = CPU::Emulator::Z80::Register16->new( set => sub { my $value = shift; $self->register(‘D’)->set(($value & 0xFE00) >> 8); $self->register(‘E’)->set($value & 0xFF); } ); my $register_BC_ = CPU::Emulator::Z80::Register16->new( set => sub { my $value = shift; $self->register(‘B_’)->set(($value & 0xFE00) >> 8); $self->register(‘C_’)->set($value & 0xFF); } ); my $register_DE_ = CPU::Emulator::Z80::Register16->new( set => sub { my $value = shift; $self->register(‘D_’)->set(($value & 0xFE00) >> 8); $self->register(‘E_’)->set($value & 0xFF); } ); And then the code explodes We need Refactoring-Man!

  14. Closures for Fun: CPU::Emulator::Z80 package CPU::Emulator::Z80; … my $register_BC = $self->_derive_register16(qw(B C)); my $register_DE = $self->_derive_register16(qw(D E)); … # factory method sub _derive_register16 { my($self, $high, $low) = @_; return CPU::Emulator::Z80::Register16->new( get => sub { $self->register($high)->get() * 256 + $self->register($low)->get() }, set => sub { my $value = shift; $self->register($high)->set($value >>8); $self->register($low)->set($value & 0xFF); } ); } You can close over multiple variables

  15. Closures for Fun: CPU::Emulator::Z80 Closures reduced the amount of code Fewer cut n’ paste bugs Easier to update if a bug is found

  16. Closures for Profit: Sort::MultipleFields Inspired by something I needed at work and wrote a much less elegant solution for Sort lists of hashrefs Also on the CPAN

  17. Closures for Profit: Sort::MultipleFields Lets you sort this data … { author => 'Wall, Larry', title => 'Learning Perl’, … }, { author => 'Hoyle, Fred', title => 'Black Cloud, The' }, { author => 'Clarke, Arthur` C', title => 'Rendezvous with Rama' }, { author => 'Clarke, Arthur C', title => 'Islands In The Sky' } Like this … my @sorted = mfsort { author => 'ascending', # shortcut for sub { $_[0] cmp $_[1] } title => 'ascending’ } @unsorted;

  18. Closures for Profit: Sort::MultipleFields Or like this … my @sorted = mfsort { author => 'asc', title => 'asc', year => 'desc', }@unsorted; colour => sub { my @in = map { $_ eq 'red' ? 0 : $_ eq 'orange' ? 1 : $_ eq 'yellow' ? 2 : $_ eq 'green' ? 3 : $_ eq 'blue' ? 4 : $_ eq 'indigo' ? 5 : 6 } @_; $in[0] <=> $in[1]; }

  19. Closures for Profit: Sort::MultipleFields mfsort’s heart: my $sortsub = mfsortmaker($spec); @records = sort { $sortsub->($a, $b) } @records; sub mfsortmaker { my $spec = shift; my @spec = $spec->(); my $sortsub = sub($$) { 0 }; # default is to not sort at all - a No-Op while(@spec) { # eat this from the end towards the beginning my($spec, $field) = (pop(@spec), pop(@spec)); if(!ref($spec)) { # got a string, turn it into a function-ref $spec = ($spec =~ /^asc(ending)?$/i) ? sub { $_[0] cmp $_[1] } : ... } my $oldsortsub = $sortsub; $sortsub = sub($$) { $spec->($_[0]->{$field}, $_[1]->{$field}) || $oldsortsub->($_[0], $_[1]) } } # extra layer of wrapping seems to prevent segfaults in 5.8.8. WTF? # return $sortsub return sub($$) { $sortsub->(@_) }; }

  20. Closures for Fun and Profit Summary A closure is a more “codey” sort of object They are not magic (merely sufficiently advanced technology) They are not scary You can do a lot with very little code Which means less debugging (which is good, cos debugging’s Hard) So let’s go shopping! I recommend buying Higher Order Perl, ISBN 1558607013

More Related