Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Perl object ?

270 views

Published on

Why, when and how use objects with Perl

Published in: Software
  • Login to see the comments

  • Be the first to like this

Perl object ?

  1. 1. Perl Object ? SLC.pm October 2015 Perl Object Nicolas Rochelemagne
  2. 2. Perl Object ? •Why ? •When ? •How ?
  3. 3. Without objects we manipulate scalars, arrays, hashes... $hash = {         key => 42,         another => {                 one  => 43,                 deep => {                         here => {                                 you => {                                         can => 'find me'                                 }                         }                 },                 str  => "Data value"         },         elts => [ 8, 25, 37, 64 ] }; this lead to store data in /ugly/ hashes
  4. 4. Problems with this approach : you need to know the "exact key" to use... $hash->{key} = 42; $hash->{anotherlevel}->{key} = "value"; $hash->{where}->{can}{be}{mykey} = { it => 's there' }; deep research into the code... or need to dump huge hash
  5. 5. You can s/confound/mispell/ key name somewhere sub method {         my $h = shift;         $h->{key} = 42; } then later ...         $h->{keys}++ and $h->{kyes} = 51; ...
  6. 6. You cannot change the key name or storage level cannot become neither $hash->{current_key} = 42; nor $hash->{updated_key} = 42; $hash->{better}{key} = 42; without updating the full code !
  7. 7. You cannot control life cycle of an attribute : sub somewhere {         ...         $hash->{mykey} = 42 and additionnal_operation;         ... } sub otherplace {         ...         $hash->{mykey} = 43 and additionnal_operation;         ... } •on create •on update •before, after, around •hooks : innner, augment... without objects
  8. 8. You would need an accessor it should be the only single way
 to access to this piece of data sub mykey {         my ($self, $value) = @_;         if (defined $value) {                 $self->{_mykey} = $value;                 $self->additionnal_operation();         }                 $self->{_mykey}; }
  9. 9. Writing documentation =pod =head attribute Parameters : attribute value ( optional ) Description : attribute method can be used to read or update it ! Returns : current value Usage :         # use as reader         my $read = $object->attribute();         # use as writter         $object->attribute($new_value); =cut         sub attribute {                 ... some code there ( or not ! )         } ... is difficult rather than Please use $object->{level1}{level2} to access the expected value ! # at this time, and it could never change ?
  10. 10. What is an object ? •functions •data Small piece of code
  11. 11. Why object / module ? •code is organized •Object is DRY, Lazy & Fun •code is easier to read / share •design & development can be dissociate •easier to test •provides fault containment •reduce code maintenance •simplify product evolution •documentation is easier
  12. 12. Code organization Object |__ Human | |___ Male | |___ Female | |__ Transport |___ Car |___ Plane |___ Bicycle #!perl package Object::Transport::Car;
  13. 13. DRY : Do not Repeat Yourself  package Document::Page;   sub create {       my $self = shift;       ...         do_some_stuff; # inner();       ...   }   package Document::Special;   extends 'Document::Page';   augment 'create' => sub {       my $self = shift;       $self->do_some_extra_stuff;   }; •inheritance help you factorize your code •roles ( ~ interface )
  14. 14. Lazy package Person; use Moose; # or any other object module has 'age'    => ( is => 'rw', isa => 'Int', default => 42 );   package main; my $p = Person->new() or Person->new(age => 64); $current_age = $p->age(); $p->age($new_age); •provide "new" method •provide accessors •parameters validation :
 types, optional, default value...
  15. 15. Type checking  package Person;   use Try::Tiny;   use Moose;   use Moose::Util::TypeConstraints;   subtype 'Sex'       => as 'Str'       => where { $_ =~ m{^[mf]$}s };   has 'sex'    => ( is => 'ro', isa => 'Sex', required =>  1 );   has 'age'    => ( is => 'rw', isa => 'Int', default  => 42 );     my $person = Person->new( sex => 'm', age => 45 );   try {         Person->new( sex => 'unknown' );   } catch {          warn "Error has been detected";   };
  16. 16. Coercion package My::Types::Date; use Moose::Util::TypeConstraints; use DateTime; # ... subtype 'MyType:Day' => as 'DateTime'; coerce  'MyType:Day' => from 'Str' => via {     /^d{4}d{2}d{2}$/ or croak "Unable to coerce '$_' into a valid date";     return DateTime::Format::DateParse->parse_datetime($_); }; package Test::Coerce; use Moose; use My::Types::Date; has day => ( is  => 'rw', isa => 'MyType:Day',         coerce => 1); package main; my $d1 = Test::Coerce->new(day => DateTime->now()); my $d2 = Test::Coerce->new(day => '20111130'); isa_ok $d2->day, 'DateTime', 'day is coerced to a DateTime object';
  17. 17. Which object library to choose ? •Moose •Mouse •Moo •Mo •M •... •fields •Object::Tiny(::XS) •Class::XSAccessor •write your own simple Object ? and sometimes none
  18. 18. •the most advanced •large ecosystem of extensions : 
 MooseX : validate, getopt, singleton, types... •can use advanced types and coercion methods •hooks : before, after, inner, augment... •startup time •memory usage •dependencies... Moose : the fat one ! fat but so good... Advantages : Disadvantages :
  19. 19. •same goal as Mouse : provide a Moose lighter •but provide "as little as possible" : minimalist Moo : the light one ! package Demo::Moo; use Moo; with 'Some::Role'; has bar => (         is => 'rw',         isa => sub { $_[0] =~ /^[+-]?d+$/ },         coerce => quote_sub q{ $_[0] + 1 unless $_[0] % 2 },         lazy => 1, ); •can use only one role at a time •not available : super, override, inner, augment •no initializer Start with Moo and if you need more, switch to Mouse / Moose
  20. 20. •use Class::XSAccessor •fast, easy but extremely limited •only implement getters •do not provide setters Object::Tiny[::XS] : The fast one ! package MyClass; use Object::Tiny::XS qw{ list of attributes }; 1;   package main; my $object = MyClass->new( list => [ 42, 51 ], of => 'numbers' ); say join(',', @{$object->list}, $object->of); eval { $object->attributes( 63 ); } or warn "Update value failed !";
  21. 21. Writing your own object module ? package My::Object; # Inspired from Object::Tiny sub import {     return unless shift eq __PACKAGE__;     my $pkg = caller;     @{"${pkg}::ISA"} = 'My::Object';     map {         my $method = "${pkg}::$_";         my $code = _get_accessor_for($_);         { no strict 'refs'; *$method = $code; }     } @_;     return 1; } sub _get_accessor_for {     my ($key) = @_;     return unless caller eq __PACKAGE__; # Did I say private ?            defined $key and !ref $key and $key =~ /^[^Wd]w*z/s or croak("Invalid key '$key'");     sub {         my ($self, $v) = @_;         $self->{$key} = $v if defined $v;         $self->{$key};     }; } sub new {     my $class = shift;     bless { @_ }, $class; } # that’s all !
  22. 22. Using your own object module package main; # initialize your object using new method my $elt  = MyClass->new(list => [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]); # getter available my $list = $elt->list; # setter available $elt->of('numbers'); package MyClass; use My::Object qw{ list of attributes }; # that's all you need ! create a class start playing with it
  23. 23. Extreme performance with Class::XSAccessor package SuperFast; use Class::XSAccessor     replace     => 1,     constructor => 'new',     accessors => {         speed => 'speed',     },     predicates => {         has_speed => 'speed', }; package main; my $o = SuperFast->new(speed => 'flash'); is($o->speed, 'flash'); $o->speed('max') and say $o->speed; is($o->speed, 'max'); •Fast read & write •provide accessors, getters, setters and predicates •use Devel::PPPort Perl Pollution Portability
  24. 24. Still want to keep using [better] hash ? package Animal::Sounds; use fields qw(cat dog bird); sub new {     my Animal::Sounds $self = shift;     $self = fields::new($self) unless ref $self;     return $self; } package main; my Animal::Sounds $sound = Animal::Sounds->new(); # typed lexical $sound->{cat}   = 'miaaooo'; # ok $sound->{horse} = 'hiia'; # generates compile-time error   # No such class field "horse" in variable $sound of type Animal::Sounds fields builtin provide compile-time class Objects ( typed ) with named fields are as compact and as fast arrays to access
  25. 25. fields limit # extract from field.pm *new = sub {         my $class = shift;         $class = ref $class if ref $class;         require Hash::Util;         my $self = bless {}, $class;                                                 # The lock_keys() prototype won't work since we require Hash::Util :(         &Hash::Util::lock_keys(%$self, _accessible_keys($class));     # spent  6.00s making 20172 calls to Hash::Util::lock_keys, avg 297us/call     # spent 710ms making 20172 calls to fields::_accessible_keys, avg 35us/call         return $self; } be careful in production ( perl >= 5.009 ) Trick : mock *fields::new depending on current env
 or switch to another object module 121     13.3ms 122     7.62ms 123     20.9ms 124     35.2ms 125     126     127     6.71s 128     61.6ms 129 •provides fast read access to attributes •slow on object creation
  26. 26. Control hash life cycle package main; use Human; use Test::More; my $john = Human->new; $john->{age} = 45; is($john->{age}, 45, "nothing special"); $john->{age} = 123; is($john->{age}, 99, "what happens there ?"); Still want to use hash ? How is it possible ?
  27. 27. Use tie to hook package Human; sub TIESCALAR { die unless(ref $_[1] eq 'CODE'); my $cod=$_[1]; bless $cod, $_[0]; } sub STORE { my $self = shift; $self->(@_); } sub FETCH { shift->(); } # many more available : DELETE, CLEAR, EXISTS, NEXTKEY... sub new {     my $class = shift;     my $self = bless {}, $class;     my $age;     tie $self->{age}, __PACKAGE__, sub {         my ($value) = @_;         return $age unless defined $value;         warn "You looks too old" and $value = 99 if $value >= 100;         $age = $value;         return $age;     };     $self; } You can also tie array, hash...
  28. 28. When we should not choose object ? "Premature optimization is the root of all evil" Tony Hoare •performance ? •difficult to learn ? •need to create too many objects ? •do not like abstraction ?
  29. 29. Performance problems ? 1/ Analyze the problem origin •waiting for database •waiting for IO •CPU usage •Memory usage •.... use Devel::NYTProf 2/ then apply the correct solution •use parallel algorithm / poe •use inline C / XS •do not use object •...
  30. 30. Object Benchmark Moo : best average solution ( also consider Mouse ) Class::XSAccessor : performance fields : when many update and few object creation needed
  31. 31. Common Errors & Tricks •make Moose package immutable
 no Moose; __PACKAGE__->meta->make_immutable(); •object creation is time consuming :
 use cache or singleton if possible •use factory for abstraction •fields use Hash::Util::Lock
 # bad idea if too many objects creation •be careful with Time syscall, try to share it :
 my $now = Datetime->now(); •be careful with coercion
 # do not try to do too much ~ /black mag/ic
  32. 32. Thanks atoomic@cpan.org

×