Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Meditations

( #480=superdoc: print w/ replies, xml ) Need Help??

If you've discovered something amazing about Perl that you just need to share with everyone, this is the right place.

This section is also used for non-question discussions about Perl, and for any discussions that are not specifically programming related. For example, if you want to share or discuss opinions on hacker culture, the job market, or Perl 6 development, this is the place. (Note, however, that discussions about the PerlMonks web site belong in PerlMonks Discussion.)

Meditations is sometimes used as a sounding-board — a place to post initial drafts of perl tutorials, code modules, book reviews, articles, quizzes, etc. — so that the author can benefit from the collective insight of the monks before publishing the finished item to its proper place (be it Tutorials, Cool Uses for Perl, Reviews, or whatever). If you do this, it is generally considered appropriate to prefix your node title with "RFC:" (for "request for comments").

User Meditations
The sieve of Xuedong Luo (Algorithm3) for generating prime numbers
5 direct replies — Read more / Contribute
by marioroy
on Jun 11, 2015 at 00:34

    Update June 26, 2015: New results using Math::Prime::Util v0.51 at the end of the post.

    Some time ago traveled to an imaginary place filled with prime numbers. In one of the paintings was the following statement. With k initialized to 1, the value alternates from 2 to 1 repeatedly. It was this statement which inspired me to give Algorithm3 a try.

    k = 3 - k;

    There are various prime modules on CPAN. Thus, have no plans to create another. All I wanted to do was to compare the Sieve of Eratosthenes with Algorithm3. I created a local copy of Math::Prime::FastSieve by davido and replaced the primes function.

    Sieve of Eratosthenes

    /* Sieve of Eratosthenes. Return a reference to an array containing a +ll * prime numbers less than or equal to search_to. Uses an optimized s +ieve * that requires one bit per odd from 0 .. n. Evens aren't represente +d in the * sieve. 2 is just handled as a special case. */ SV* primes( long search_to ) { AV* av = newAV(); if( search_to < 2 ) return newRV_noinc( (SV*) av ); // Return an empty list ref. av_push( av, newSVuv( 2UL ) ); // Allocate space for odd numbers (15 bits per 30 values) sieve_type primes( search_to/2 + 1, 0 ); // Sieve over the odd numbers for( sieve_size_t i = 3; i * i <= search_to; i+=2 ) if( ! primes[i/2] ) for( sieve_size_t k = i*i; k <= search_to; k += 2*i) primes[k/2] = 1; // Add each prime to the list ref for( sieve_size_t i = 3; i <= search_to; i += 2 ) if( ! primes[i/2] ) av_push( av, newSVuv( static_cast<unsigned long>( i ) ) ); return newRV_noinc( (SV*) av ); }

    Sieve of Xuedong Luo (Algorithm3)

    /* Sieve of Xuedong Luo (Algorithm3). Return a reference to an array * containing all prime numbers less than or equal to search_to. * * A practical sieve algorithm for finding prime numbers. * ACM Volume 32 Issue 3, March 1989, Pages 344-346 * http://dl.acm.org/citation.cfm?doid=62065.62072 * * Avoid all composites that have 2 or 3 as one of their prime factors * where i is odd. * * { 0, 5, 7, 11, 13, ... 3i + 2, 3(i + 1) + 1, ..., N } * 0, 1, 2, 3, 4, ... list indices (0 is not used) */ SV* primes( long search_to ) { AV* av = newAV(); if( search_to < 2 ) return newRV_noinc( (SV*) av ); // Return an empty list ref. sieve_size_t i, j, q = (sieve_size_t) sqrt((double) search_to) / 3 +; sieve_size_t M = (sieve_size_t) search_to / 3; sieve_size_t c = 0, k = 1, t = 2, ij; // Allocate space. Set bits to 1. Unset bit 0. sieve_type primes( M + 2, 1 ); primes[0] = 0; // Unset bits greater than search_to. if ( 3 * M + 2 > search_to + ((sieve_size_t)search_to & 1) ) primes[M] = 0; if ( 3 * (M + 1) + 1 > search_to + ((sieve_size_t)search_to & 1) ) primes[M + 1] = 0; // Clear composites. for ( i = 1; i <= q; i++ ) { k = 3 - k, c = 4 * k * i + c, j = c; ij = 2 * i * (3 - k) + 1, t = 4 * k + t; if ( primes[i] ) { while ( j <= M ) { primes[j] = 0; j += ij, ij = t - ij; } } } // Gather primes. if( search_to >= 2 ) av_push( av, newSVuv( 2UL ) ); if( search_to >= 3 ) av_push( av, newSVuv( 3UL ) ); for ( i = 1; i <= M; i += 2 ) { if ( primes[i] ) av_push( av, newSVuv(static_cast<unsigned long>(3 * i + 2)) +); if ( primes[i + 1] ) av_push( av, newSVuv(static_cast<unsigned long>(3 * (i + 1) ++ 1)) ); } return newRV_noinc( (SV*) av ); }

    Below is the time taken to find all prime numbers smaller than 1 billion.

    my $primes = primes( 1_000_000_000 ); Sieve of Eratosthenes 4.879 seconds Sieve of Xuedong Luo 3.751 seconds There are 50,847,534 prime numbers between 1 and 1 billion.

    I was so fascinated by Algorithm3 that I decided to parallelize it. It took me 5 weekends just to get the math to work. But I wanted faster and placed it aside. Two years later tried again and created Sandboxing with Perl + MCE + Inline::C. Also, tried Math::Prime::Util by Dana Jacobsen and primesieve by Kim Walisch.

    Testing was done on a Haswell Core i7 Macbook Pro running at 2.6 GHz configured with 1600 MHz memory.

    # # Count primes # perl algorithm3.pl 1_000_000_000 Prime numbers : 50847534 Compute time : 0.146 sec perl primesieve.pl 1_000_000_000 Prime numbers : 50847534 Compute time : 0.064 sec perl primeutil.pl 1_000_000_000 Prime numbers : 50847534 Compute time : 0.024 sec # # Sum primes ( 203_280_221 prime numbers ) # perl algorithm3.pl 4_294_967_296 --sum Sum of primes : 425649736193687430 Compute time : 1.082 sec perl primesieve.pl 4_294_967_296 --sum Sum of primes : 425649736193687430 Compute time : 0.369 sec perl primeutil.pl 4_294_967_296 --sum Sum of primes : 425649736193687430 Compute time : 2.207 sec # # Print primes ( 2.0 GB, beware... ) # perl algorithm3.pl 4_294_967_296 --print >/dev/null Compute time : 2.071 sec perl primesieve.pl 4_294_967_296 --print >/dev/null Compute time : 1.395 sec perl primeutil.pl 4_294_967_296 --print >/dev/null Compute time : 13.470 sec

    Fast is possible in Perl. Thus, Perl is fun. One is not likely to print that many prime numbers. Math::Prime::Util is powerful with many features. Algorithm3 was mainly an exercise exploring Perl + MCE + Inline::C possibilities.

    Update June 26, 2015 using Math::Prime::Util v0.51

    The mce-sandbox was updated to call the new sum_primes/print_primes functions in Math::Prime::Util v0.51 for the primeutil.pl example.

    Count primes $ perl algorithm3.pl 4294967296 Prime numbers : 203280221 Compute time : 0.623 sec $ perl primesieve.pl 4294967296 Prime numbers : 203280221 Compute time : 0.252 sec $ perl primeutil.pl 4294967296 Prime numbers : 203280221 Compute time : 0.210 sec Sum of primes $ perl algorithm3.pl 4294967296 --sum Sum of primes : 425649736193687430 Compute time : 1.090 sec $ perl primesieve.pl 4294967296 --sum Sum of primes : 425649736193687430 Compute time : 0.367 sec $ perl primeutil.pl 4294967296 --sum Sum of primes : 425649736193687430 Compute time : 0.768 sec Print primes ( outputs 2 GB containing 2032802221 prime numbers ) $ perl algorithm3.pl 4294967296 --print >/dev/null Compute time : 2.086 sec $ perl primesieve.pl 4294967296 --print >/dev/null Compute time : 1.397 sec $ perl primeutil.pl 4294967296 --print >/dev/null Compute time : 1.925 sec

    Kind regards, Mario

A "Fun"ctional Attempt
2 direct replies — Read more / Contribute
by withering
on Jun 04, 2015 at 04:14

    Perl is somewhat functional itself -- if the concept, "functional", which we're talking about, mainly means using functions as first-class objects instead of wiping almost all side effects out. However, lacking of sugar such as useful prototypes, pattern matching, or list comprehensions makes Perl less attractive in some functional situation (for fun, perhaps).

    There are a few attempts I made to achieve a better experience when programming perl for fun. For example:

    #!/usr/bin/env perl use HOI::Comprehensions; use HOI::Match; sub slowsort { HOI::Match::pmatch( 'nil' => sub { [] }, 'pivot :: unsorted' => sub { my $left = HOI::Comprehensions::comp( sub { $x }, x => $un +sorted )->( sub { $x <= $pivot } ); my $right = HOI::Comprehensions::comp( sub { $x }, x => $u +nsorted )->( sub { $x > $pivot } ); [ @{slowsort($left->force)}, $pivot, @{slowsort($right->fo +rce)} ] }, )->(@_) } my $res = slowsort [3, 4, 1, 2, 5, 6]; print @$res, "\n";

    where HOI::Match and HOI::Comprehensions are used to give a simple description of the whole computation. It should be noted that the code is not so strict since it assumes the existence of local variables. Scopes are dynamic, and bound variables are bound by names, as the ones in a typical lambda calculus theory.

    It is still not clear to me whether such sugar ideas are welcomed or not. Any suggestion or criticism is welcomed. I am looking forward for your replies.

Happy Monk day. (To me!)
12 direct replies — Read more / Contribute
by BrowserUk
on Jun 03, 2015 at 22:20

    I just realised that it's 13(*) years to the day since I posted this. We all start somewhere. I've been here almost every day since.

    *13. Is this the year it all goes wrong?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Net::FTP fail workaround
1 direct reply — Read more / Contribute
by kurgan
on Jun 03, 2015 at 07:50

    I ran into an issue where Net::FTP was failing at random while connecting many times over the life of a script. I searched for a solution only to find that others were having similar issues. It seems that this excellent module does not actually check to see if the port that is used for connection is working correctly before forging on. The only way around it (that I have found) was to check for the error and reconnect on-the-fly until a working port has been found. It is not a perfect solution as it takes extra resources that could be used elsewhere if the error check was done at the module level, but it has worked well for me so far.

    I just thought others might find this of some help if they find themselves in the same situation. I was not really sure where to post this, so I asked on the CB and pointed here (thank you all for the help!). If you all find this helpful at all, please share it with others at your pleasure.

What's new in ECMAScript6, or: Oh no! Don't steal syntax from Perl!
4 direct replies — Read more / Contribute
by FreeBeerReekingMonk
on May 29, 2015 at 12:49

    Harmony... that's what the upcomming JS is called. It has some new syntax... and it's perl syntax... but does something totally different! So let me show you why I will be confused for the years to come:
    These 2 things are equivalent:

    people.map(function (person) { return person.age; })); people.map(person => person.age);
    Why? Why a fat arrow... why not the other way? <=

    Then there is let, which is similar to my but you seem to still be able to mix var in and create a scope mess...

    They also use modules, with named import's (just like in perl you can require certain things from a pm).
    And the templating... oh noes... the templating uses backtick/backquote...
    var name = 'John'; var age = 29; return `My name is ${ name }, in a year I will be ${ age + 1 } years o +ld`;

    Interested in reading more about JS6? Here is a link:
    ecmascript6-introduction

    Now leave me be... I'm drowning my pain in beer...

perl Data structure to XML
1 direct reply — Read more / Contribute
by Hosen1989
on May 27, 2015 at 07:50

    perl Data structure to XML

    Hi ALL.

    I like to share with you solution for issue I had face it and come with way to solve it.

    I was in need of some module that take any kind of hash or array or any combination of those two and convert them to xml file.

    will, yes there are other module that do this task but not as need it.

    so here my way to do this task:

    also please point to any error in my code or any other best way to do the same thing. ^_^

    use strict; use warnings; use XML::LibXML; my %TV = ( flintstones => { series => "flintstones", nights => [ "monday", "thursday", "friday" ], members => [ { name => "fred", role => "husband", age => 36, }, { name => "wilma", role => "wife", age => 31, }, { name => "pebbles", role => "kid", age => 4, }, ], }, jetsons => { series => "jetsons", nights => [ "wednesday", "saturday" ], members => [ { name => "george", role => "husband", age => 41, }, { name => "jane", role => "wife", age => 39, }, { name => "elroy", role => "kid", age => 9, }, ], }, simpsons => { series => "simpsons", nights => [ "monday" ], members => [ { name => "homer", role => "husband", age => 34, }, { name => "marge", role => "wife", age => 37, }, { name => "bart", role => "kid", age => 11, }, ], }, ); my $xmlString = HASH2XML(\%TV,'TV_SERIES'); print $xmlString; ###################################################################### +######################## sub HASH2XML{ my ($inHashRef) = $_[0]; my ($inName) = $_[1]; if(!defined $inName){$inName = 'rootNode';} my $doc = XML::LibXML::Document->new('1.0', 'utf-8'); # to + create XML doc my $rootNode = $doc->createElement("$inName"); # to create xml +root node $rootNode->setAttribute('Profile_id'=> "$inName"); # add some A +ttribute to the node _OBJ2XML_($doc,$rootNode,$inHashRef,$inName); $doc->setDocumentElement($rootNode); # print $doc->toString(); return $doc->toString(1); } sub _OBJ2XML_{ my ($doc) = $_[0]; my ($inNode) = $_[1]; my ($inRef) = $_[2]; my ($inName) = $_[3]; if(!defined $inName){$inName = 'Node';} if(ref($inRef) eq 'HASH'){ for my $key (sort keys %{$inRef}) { if(ref($inRef->{$key}) eq 'HASH'){ my $tag = $doc->createElement($key); # $tag->setAttribute('dataType'=> "HASH"); $inNode->appendChild($tag); _OBJ2XML_($doc,$tag,$inRef->{$key},$key); }else{ _OBJ2XML_($doc,$inNode,$inRef->{$key},$key); } } }elsif(ref($inRef) eq 'ARRAY'){ my $Len = @{$inRef}; for(my $i = 0; $i < $Len; $i++){ if(ref(@{$inRef}[$i]) eq 'HASH' or ref(@{$inRef}[$i]) eq ' +ARRAY'){ my $tag = $doc->createElement($inName); # $tag->setAttribute('dataType'=> "ARRAY"); $inNode->appendChild($tag); _OBJ2XML_($doc,$tag,@{$inRef}[$i],$inName); }else{ _OBJ2XML_($doc,$inNode,@{$inRef}[$i],$inName); } } }elsif(ref($inRef) eq 'CODE'){ print "--End to CODE ref @ LINE:".__LINE__."\n"; return 0; }elsif(ref($inRef) eq 'SCALAR'){ print "--End to SCALAR ref @ LINE:".__LINE__."\n"; return 0; }else{ my $tag = $doc->createElement($inName); # $tag->setAttribute('dataType'=> "data"); $tag->appendTextNode($inRef); $inNode->appendChild($tag); return 0; } return 0; }

    -----------------------------------------------------------------

    and below is the sample for the output:

    # ------------------------------------------# # the XML output after doing pretty print # # ------------------------------------------# <?xml version="1.0" encoding="utf-8"?> <TV_SERIES Profile_id="TV_SERIES"> <flintstones> <members> <age>36</age> <name>fred</name> <role>husband</role> </members> <members> <age>31</age> <name>wilma</name> <role>wife</role> </members> <members> <age>4</age> <name>pebbles</name> <role>kid</role> </members> <nights>monday</nights> <nights>thursday</nights> <nights>friday</nights> <series>flintstones</series> </flintstones> <jetsons> <members> <age>41</age> <name>george</name> <role>husband</role> </members> <members> <age>39</age> <name>jane</name> <role>wife</role> </members> <members> <age>9</age> <name>elroy</name> <role>kid</role> </members> <nights>wednesday</nights> <nights>saturday</nights> <series>jetsons</series> </jetsons> <simpsons> <members> <age>34</age> <name>homer</name> <role>husband</role> </members> <members> <age>37</age> <name>marge</name> <role>wife</role> </members> <members> <age>11</age> <name>bart</name> <role>kid</role> </members> <nights>monday</nights> <series>simpsons</series> </simpsons> </TV_SERIES>
Is CGI.pm dead?
5 direct replies — Read more / Contribute
by Anonymous Monk
on May 26, 2015 at 07:08

    Hello, I've found out that CGI.pm is no more in the core distribution of Perl. I've also read that there are many better ways to implement a web application, like use Plack, or use CGI::Application, CGI::Snapp, Dancer, Mojolicious... It is also suggested to use templating systems (ok fine, I've used them with CGI.pm).

    However, with modern responsive websites I think that CGI.pm is still a great module, so simple to use it that I don't see a reason to move away or use anything else.

    You just write an API for the client javascript making an AJAX request and you're all done with something like:

    #!/usr/bin/perl use strict; use CGI; use JSON; my $query = new CGI; my $response = whatever(Query=>$query); my $json = JSON->new->utf8(1)->pretty(1)->allow_nonref->encode($respon +se); print $query->header('application/json').$json; sub whatever { # Here you can do REALLY anything, and send back an hash reference }

    Do I make it too easy? This is has a flat learning curve too.

Perl monks vs other sites
3 direct replies — Read more / Contribute
by f77coder
on May 23, 2015 at 23:09
    Hello All,

    I wasn't sure where to post this, so apologies if this is not the place.

    I wanted to say how great Perl Monks is at helping out noobs compared with knuckle dragging neanderthals at place like stack overflow. People here are generally orders of magnitude nicer.

    Cudos to the site.

RFC: Swagger-codegen for Perl
2 direct replies — Read more / Contribute
by wing328
on May 15, 2015 at 02:17
    Hi all,

    https://github.com/swagger-api/swagger-codegen contains a template-driven engine to generate client code in different languages by parsing your Swagger Resource Declaration. Recently I've added the Perl template. To test the code generation, please perform the following (assuming you've the dependencies installed):

    git clone https://github.com/swagger-api/swagger-codegen.git git checkout develop_2.0 git checkout mvn clean && ./bin/perl-petstore.sh

    If you do not want to install the dependencies and just want to get a peek at the auto-generated Perl SDK, please go to the directory samples/client/petstore/perl to have a look at the Perl SDK for Petstore http://petstore.swagger.io (please make sure you're in the develop_2.0 branch)

    The Perl SDK is not perfect and I would appreciate your time to test and review, and share with me your feedback.

    (ideally I would like to post this at "Meditations" but I couldn't find a way to post there)

    Best,
    wing328
    http://github.com/wing328
OOP: How to (not) lose Encapsulation
3 direct replies — Read more / Contribute
by Arunbear
on May 12, 2015 at 08:25

    Introduction

    Moose and its smaller cousin Moo have become popular ways of creating Object Oriented code, but the existing tutorials do not have much to say about Information hiding (also known as Encapsulation), so this is an attempt to fill that gap.

    Alice and the Set

    Alice wants to use a Set (a collection of unique items) to keep track of data her program has already seen. She creates a Set class which initially looks like this (assume that she either hasn't learnt about hashes yet, or doesn't like the "fiddliness" of simulating a Set via a Hash):
    package Set; use Moo; has 'items' => (is => 'ro', default => sub { [ ] }); no Moo; sub has { my ($self, $e) = @_; scalar grep { $_ == $e } @{ $self->items }; } sub add { my ($self, $e) = @_; if ( ! $self->has($e) ) { push @{ $self->items }, $e; } } 1;
    It can be used like this:
    % reply 0> use Set 1> my $s = Set->new $res[0] = bless( { 'items' => [] }, 'Set' ) 2> $s->has(42) $res[1] = 0 3> $s->add(42) $res[2] = 1 4> $s->has(42) $res[3] = 1

    Bob, min and max

    Another programmer Bob, starts using this class. Bob finds it useful but misses the ability to find the min/max element of a set, so he creates some utilities:
    package BobUtil; use strict; use List::Util qw(min max); sub set_min { my ($set) = @_; min @{ $set->items }; } sub set_max { my ($set) = @_; max @{ $set->items }; } 1;
    which he can use like so:
    % reply 0> use Set 1> use BobUtil 2> my $s = Set->new $res[0] = bless( { 'items' => [] }, 'Set' ) 3> $s->add($_) for 1 .. 5 $res[1] = '' 4> BobUtil::set_min($s) $res[2] = 1 5> BobUtil::set_max($s) $res[3] = 5
    Bob eventually finds this usage too cumbersome and decides to make it simpler by using Inheritance to create his own set:
    package BobSet; use Moo; use List::Util qw(min max); extends 'Set'; no Moo; sub numeric_min { my ($self) = @_; min @{ $self->items }; } sub numeric_max { my ($self) = @_; max @{ $self->items }; } 1;
    And now he can do this:
    % reply 0> use BobSet 1> my $s = BobSet->new $res[0] = bless( { 'items' => [] }, 'BobSet' ) 2> $s->add($_) for 1 .. 5 $res[1] = '' 3> $s->numeric_min $res[2] = 1 4> $s->numeric_max $res[3] = 5

    Alice updates the Set

    Now realising that linear scans don't scale up as well as hash lookups, Alice decides to update her Set class to use a hash rather than an array:
    package Set; use Moo; has 'items' => (is => 'ro', default => sub { { } }); no Moo; sub has { my ($self, $e) = @_; exists $self->items->{ $e }; } sub add { my ($self, $e) = @_; if ( ! $self->has($e) ) { $self->items->{ $e } = 1; } } 1;
    News of the new improved Set reaches Bob, and he installs the new version, but alas:
    % reply 0> use BobSet 1> my $s = BobSet->new $res[0] = bless( { 'items' => {} }, 'BobSet' ) 2> $s->add($_) for 1 .. 5 $res[1] = '' 3> $s->numeric_min Not an ARRAY reference at BobSet.pm line 11.
    And BobUtil is just as broken:
    % reply 0> use Set 1> use BobUtil 2> my $s = Set->new $res[0] = bless( { 'items' => {} }, 'Set' ) 3> $s->add($_) for 1 .. 5 $res[1] = '' 4> BobUtil::set_min($s) Not an ARRAY reference at BobUtil.pm line 8.

    Encapsulation lost via accessor

    By making the internal representation of the Set public, anyone depending on that representation will be in trouble if the representation changes. Alice updates the Set again to correct this design error:
    package Set; use Moo; has '_items' => (is => 'ro', default => sub { { } }); no Moo; sub items { my ($self) = @_; [ keys %{ $self->_items } ]; } sub has { my ($self, $e) = @_; exists $self->_items->{ $e }; } sub add { my ($self, $e) = @_; if ( ! $self->has($e) ) { $self->_items->{ $e } = 1; } } 1;
    Here the internal representation of the Set is made "private" via the "leading underscore" convention, and a public method is provided to access (a copy of) the set items (it would be better to not have an accessor for the set items, as there would be no need to rely on a convention for privacy, but this is beyond the power of Moo). And now BobSet works once again:
    % reply 0> use BobSet 1> my $s = BobSet->new $res[0] = bless( { '_items' => {} }, 'BobSet' ) 2> $s->add($_) for 1 .. 5 $res[1] = '' 3> $s->numeric_min $res[2] = '1' 4> $s->numeric_max $res[3] = '5'

    Encapsulation lost via constructor

    There's still another way in which Encapsulation is lost, consider:
    % reply 0> use Set 1> my $s = Set->new(_items => [1 .. 4]) $res[0] = bless( { '_items' => [ 1, 2, 3, 4 ] }, 'Set' ) 2> $s->add(5) Not a HASH reference at Set.pm line 15.
    The constructor generated by Moo will by default allow any attribute to be set via an "init_arg", and clearly in this case it is not desirable. There are are few ways to fix this, such as constraining the value using an "isa" directive or by an "init_arg" => undef directive.

    Yet another way is to use BUILDARGS e.g.

    package Set; use Moo; has '_items' => (is => 'ro', default => sub { { } }); no Moo; sub BUILDARGS { shift; return { _items => { map { $_ => 1 } @_ } }; } sub items { my ($self) = @_; [ keys %{ $self->_items } ]; } sub has { my ($self, $e) = @_; exists $self->_items->{ $e }; } sub add { my ($self, $e) = @_; if ( ! $self->has($e) ) { $self->_items->{ $e } = 1; } } 1;
    Now any (explicit) constructor arguments will become elements of the Set:
    % reply 0> use Set 1> my $s = Set->new(1 .. 4) $res[0] = bless( { '_items' => { '1' => 1, '2' => 1, '3' => 1, '4' => 1 } }, 'Set' ) 2> $s->has(5) $res[1] = '' 3> $s->has(3) $res[2] = 1

    Encapsulation lost via Inheritance

    Yet another programmer Chuck, also starts using Alice's Set class but he finds that he wants the Set to be able to remember how many times it has encountered a given value e.g. Chuck wants to create a new type of set with this behaviour:
    % reply 0> use RememberingSet 1> $s = RememberingSet->new 3> $s->has(1) $res[1] = '' 4> $s->add(1) $res[2] = 1 5> $s->seen(1) $res[3] = 2 6> $s->seen(2) $res[4] = 0
    Here the set remembers that it has seen the value 1 twice, once via has() and once via add(), whereas it hasn't seen the value 2 via add() or has(). Chuck uses Inheritance to create this type of set
    package RememberingSet; use Moo; has '_count' => (is => 'ro', default => sub { { } }); extends 'Set'; no Moo; sub has { my ($self, $e) = @_; $self->_count->{ $e }++; $self->SUPER::has($e); } sub add { my ($self, $e) = @_; $self->_count->{ $e }++; $self->SUPER::add($e); } sub seen { my ($self, $e) = @_; exists $self->_count->{ $e } ? $self->_count->{ $e } : 0; } 1;
    The RememberingSet overrides the has() and add() methods in both cases updating a counter before calling the corresponding version in Alice's Set. But Chuck finds that this new set doesn't work as expected
    % reply 0> use RememberingSet 1> my $s = RememberingSet->new $res[0] = bless( { '_count' => {}, '_items' => {} }, 'RememberingSet' ) 2> $s->has(1) $res[1] = '' 3> $s->add(1) $res[2] = 1 4> $s->seen(1) $res[3] = 3
    This has happened because in the Set class, the add() method calls the has() method. Chuck could fix this by not updating the count in his add() method, but this is a fragile solution as seen() would yield the wrong answer if Alice decided to update add() so that it didn't call has().

    Composition

    The problem with Inheritance is that it requires Chuck to know the internal workings of Alice's set class to use it correctly (thus the loss of Encapsulation). A safer form of reuse is Composition which looks like
    package RememberingSet; use Moo; use Set; has '_count' => (is => 'ro', default => sub { { } }); has '_set' => (is => 'ro', default => sub { Set->new }); no Moo; sub has { my ($self, $e) = @_; $self->_count->{ $e }++; $self->_set->has($e); } sub add { my ($self, $e) = @_; $self->_count->{ $e }++; $self->_set->add($e); } sub seen { my ($self, $e) = @_; exists $self->_count->{ $e } ? $self->_count->{ $e } : 0; } 1;
    This solution provides the expected behaviour. Composition works by wrapping the "derived" class around the original one and forwarding (or delegating) the appropriate methods to it. There are even Moosisms like "handles" and "around" that could be be used to simplify this solution e.g.
    package RememberingSet; use Moo; use Set; my $Delegated = [qw/add has/]; has '_count' => (is => 'ro', default => sub { { } }); has '_set' => (is => 'ro', default => sub { Set->new }, handles => $ +Delegated); around $Delegated => sub { my ($orig, $self, $e) = @_; $self->_count->{ $e }++; $self->$orig($e); }; no Moo; sub seen { my ($self, $e) = @_; exists $self->_count->{ $e } ? $self->_count->{ $e } : 0; } 1;
    The REPL used in the above examples is reply

    Takeaways

    • Consider making all attributes private (if only via convention)
    • Consider turning off init_args
    • Consider using Composition instead of Inheritance
Never say never
2 direct replies — Read more / Contribute
by Lady_Aleena
on May 05, 2015 at 23:37

    A thud can be heard throughout the monastery as Lady Aleena's head hits her desk in the scriptorium. Shortly thereafter the sound of breaking glass filters through the monastery's halls as her preconceptions are shattered.

    Never say you will never do a thing because, one day, you will do the thing then feel foolish.

    Now here is some history and what happened tonight. I said I would never use pipes in my data fields. Tonight I did. Now I am feeling more than foolish. (And I've made more work for myself while trying to make less work for myself.) I just learned my lesson.

    If you feel you are about to say "I will never...", stop, think very hard, count to ten, whatever. Just do not say it! One day you will be writing a piece of code, humming a little tune stuck in your head, then you will crash into a wall because you did not take into consideration the exception you just wrote.

    Have a nice day!

    I started this thought in the CB and continued it here.

    No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
    Lady Aleena
perlnews item worth reading!
No replies — Read more | Post response
by ww
on May 05, 2015 at 16:12
10,000 days of Perl
2 direct replies — Read more / Contribute
by johnbio
on May 05, 2015 at 07:43
    Just a brief meditation on this landmark day for Perl. If the release of Perl 1.0 according to perlhist is taken as the date of birth, today Perl is 10,000 days old. As someone who has used Perl an awful lot for ... more than 7,000 days, and continues to do so, I would like to post a big Thank You and a 5-digit landmark congratulation to Perl, Larry Wall and the Community :-) I may post again in 2042.
Refactoring Perl5 with XS++
5 direct replies — Read more / Contribute
by rje
on Apr 25, 2015 at 01:06

    Last time I mused aloud about "refactoring" Perl, I referenced Chromatic's statement/challenge:

    "If I were to implement a language now, I'd write a very minimal core suitable for bootstrapping. ... Think of a handful of ops. Think very low level. (Think something a little higher than the universal Turing machine and the lambda calculus and maybe a little bit more VMmy than a good Forth implementation, and you have it.) If you've come up with something that can replace XS, stop. You're there. Do not continue. That's what you need." (Chromatic, January 2013)

    I know next to nothing about XS, so I started reading perldoc.

    I'm thinking about the problem, so if there is a question, it would be "what NOW?"

    Should I bother with thinking about bytecodes? In what sense could it be a replacement for XS? What does "replace XS" even MEAN? (i.e. perhaps it just means "remove the need to use perl's guts to write extensions, and improve the API").

    Most importantly, am I wasting people's time by asking?

    I'm trying to come up with my own answers, and learn by trying. But wisdom is in knowing that some of you guys have already thought through this. If you can help bring me up to speed, I'd appreciate it.

    UPDATE: I see even within the Lorito page, it was understood that the discussion was to some degree about Perl's API: "This is an issue of API design. If we understand the non-essential capabilities we want to support (e.g. optimization passes, etc), we can design the API so that such capabilities can be exploited but not required. - cotto "

Want to make an Everything site of your own?
1 direct reply — Read more / Contribute
by thomas895
on Apr 20, 2015 at 03:48

    Ever wanted to experiment with the engine PerlMonks is built on? I did, but it's rather difficult to install, so I thought I'd write this for anyone who wanted to give it a go themselves.

    My Perl is v5.16.2. YMMV for others.

    Requirements:

    • A MySQL/MariaDB server

    • GNU patch

    • C compiler

    • Some knowledge of how Apache works

    Estimated time: a quiet evening or so

    1. Download Apache 1.3.9 and mod_perl 1.14 from your nearest mirror, then unpack them. You may use other versions, but this guide won't apply to them.

    2. I wanted to install it all to my home directory. I ran mod_perl's Makefile.PL like so:

      perl Makefile.PL APACHE_SRC=../apache_1.39/src APACHE_PREFIX=$HOME/opt/apache1.3.9 DO_HTTPD=1 USE_APACI=1 EVERYTHING=1 PREFIX=/home/thomas/perl5
      Adjust as needed.
    3. If you have a relatively new version of gcc and a Perl v5.14 or newer, you will need to make some changes to the source. Apply this patch file to the mod_perl directory, and this one to the apache directory. It does the following (you can skip these details if you want):

      • In v5.16, $<; and friends are no longer cached. I just tried removing the problematic section that used these variables, and that seemed to work. You might not be able to run your server as root (which requires being able to change its own permissions), but I haven't checked.

      • For some reason, it was a trend to supply your own version of getline (maybe the libc one was broken, haven't looked it up) in those days. In any case, gcc complains about it, so I updated all of the code to use the Apache one. (it only affects the password utility, which is not really needed in our case, but it does cause make to fail)

      • In v5.14, you can't use the result of GvCV and friends as lvalues anymore, so I replaced the places where something was assigned to the result of that function with the appropriate _set macro, as the delta advises.

    4. Run make and make install, and go make some coffee. You can make test, too, but then also grab a sandwich.

    5. Try to start Apache as make install's instructions suggest, to make sure it works. You may need to choose a different port number, do so with the Listen and Port options in httpd.conf

      • If you installed Apache locally, you will need to modify apachectl and/or your shell startup script: make sure that the PERL5LIB environment variable is set to where mod_perl's Perl libraries are installed.

      Now for Everything else...

    6. Download this, unpack it, and follow QUICKINSTALL up to (but not yet including) the install_esite

      • When running Makefile.PL, if you want to install locally, don't forget to set PREFIX accordingly.

      • It is not necessary to let it append things to your httpd.conf, in a later step I'll show you why and what to do instead.

    7. If you have a modern mysql/mariadb, some of the SQL scripts won't work. Here is another patch to fix them.

      • It mostly has to do with the default values of the integer columns: by getting rid of the default value of a quoted zero, mysql accepts it.

      • There is also a timestamp column that has a size in the script, but mysql doesn't like that, so by getting rid of it, it works again.

    8. Now run install_esite, as QUICKINSTALL says.

    9. For some reason, index.pl only showed up as text, perhaps due to the other mod_perl settings I'd been playing with, or perhaps it was something else. I added this to httpd.conf, and then it worked:

      PerlModule Apache::Registry PerlModule Apache::DBI PerlModule CGI <Files *.pl> SetHandler perl-script PerlHandler Apache::Registry Options +ExecCGI PerlSendHeader On PerlSetupEnv On </Files>
    10. (Re)start Apache, visit /index.pl, and have lots of fun!

    If something doesn't work for you, post it below.

    Happy hacking!


    Edit: forgot the third patch

    -Thomas
    "Excuse me for butting in, but I'm interrupt-driven..."
    Did you know this software was released when I was only 3 years old? Still works, too -- I find that amazing.

Add your Meditation
Title:
Meditation:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":


  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others rifling through the Monastery: (18)
    As of 2015-07-28 17:48 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









      Results (258 votes), past polls