http://www.perlmonks.org?node_id=721555

Should Perl be better defined?

Pre vs Post Incrementing variables got me thinking and reading about the order in which operators evaluate their arguments and what they return.

This isn't the first time. I have read and contributed to various threads/discussions that hinged and sometimes came unhinged (at least some of the participants did) on understanding and misunderstanding of what operators return and the order in which they evaluate their arguments. They often begin with some surprising finding rooted in the discrepancy between what people think perl does or should do and what it actually does. While there is usually some reference to the documentation, it is sometimes ambiguous or silent on the issue and examples of what perl does are presented.

Discussions of these aspects of Perl/perl can bring out strong opinions and vigorous debate. Thus I conclude that they do not remain undefined because nobody cares about them.

So, I wonder why so much remains undocumented and whether there are advantages that outweigh the disadvantages.

I recall a post by Argel, and some followups. They impressed me at the time and they make me much less certain than I would otherwise be, whether more complete definition of Perl/perl would, in fact, be a good thing.

Yet, it seems less than ideal that so much of what perl does is undefined, leaving one with little but observation of perl itself (perl does what it does, after all) and a collection of more or less detailed, more or less abstract and more and often less accurate descriptions of what it does and why it does it.

What perl does is complex and can be difficult to understand. People often seek simple models and abstract descriptions that explain the common cases without the burden of learning all the details. These simple descriptions, if they are not too inaccurate, can be very helpful to using perl and progressing towards a more complete understanding.

One of the problems of simply studying perl to learn what perl does is that there is no distinction of the essential behaviors (what makes Perl/perl the great tool that it is) and the mere implementation detail - just one of many ways that the essential behavior could be achieved. But, maybe it is wrong to try to distinguish between essential behaviors and implementation details.

Maybe it is best to accept that perl is what it is and the documentation is only a guide. If there is a discrepancy between what the documentation says perl does and what perl actually does, maybe it is always perl that is correct and the documentation that is wrong.

In this case, perl will never have a bug merely because it does something different from what the documentation says it does. The only basis for deeming a behavior a bug would then be there is only perl as it is, with some documentation as a loose guide and the right thing to do is to study perl rather than study the documentation.

$VERSION

Many modules define a package global variable $VERSION. The value of this variable may be used by several functions outside the module. The behavior of these functions may influence how module authors choose to set this variable.

Where is $VERSION used?

use

Two forms of the arguments to use include versions:

In both cases, after the module is loaded, the VERSION method of the module is called, with the given version as argument. The default VERSION method, inherited from the UNIVERSAL class, croaks if the given version is larger than the value of the variable $Module::VERSION.

It is, therefore, important to understand how UNIVERSAL::VERSION compares version numbers.

The documentation for UNIVERSAL::VERSION says:

VERSION will return the value of the variable $VERSION in the package the object is blessed into. If REQUIRE is given then it will do a comparison and die if the package version is not greater than or equal to REQUIRE.

VERSION can be called as either a class (static) method, an object method or a function.

It doesn't say how UNIVERSAL::VERSION compares the versions. Being unspecified it may be inappropriate to depend on any particular behavior for comparison. None the less, one can look at existing implementations to see what they do.

A relevant post from John Peacock (author of version.pm) from Oct 2008. Note in particular that he says the version specified as an argument to use must be unquoted and must match the pattern /\d+(\.\d*)?/ - anything else is passed as an argument to the module's import method. But perldata contradicts this saying of v-strings that "Such literals are accepted by both require and use for doing a version check." My testing of perl 5.10.0 is consistent with the perldata description rather than John's version. It may be that older versions of perl worked as John described in Oct 2008.

The v-string arrived with perl 5.6.0. The v-string is

Should I use the version module?

Development of the version module is ongoing. John Peacock is preparing a new release for the upcoming (as of July 2009) perl 5.10.1 release.

If you use floating point version numbers (e.g. our $VERSION = 1.02;) then there is no need to use the version module.

If you use perl 5.10.0 or later, the functionality of the version module is built-in - there is no need to use the version module.

If you use versions of perl before 5.10.0 and you want to use "extended" version strings (v-strings, like v-strings but quoted or quoted strings with digits and more than one decimal point) then you can use the version module to achieve consistent results across versions of perl back to some older version of perl.

The package global variable $VERSION may be used by:

Colorize the Saints

This script is inspired by [Free Nodelet Hack] Highlight monk names accordingly their XP level. It generates a new javascript, to be pasted into HTML to show in Free Nodelet, in Free Nodelet Settings.

use strict; use warnings; use LWP::UserAgent; use HTML::TreeBuilder; my $ua = LWP::UserAgent->new(); $ua->agent("MyApp/0.1"); my $req = HTTP::Request->new(GET => 'http://perlmonks.org/?node=Saints +%20in%20our%20Book'); my $res = $ua->request($req); unless($res->is_success) { die $res->status_line; } my $tree = HTML::TreeBuilder->new(); $tree->parse($res->content); $tree->eof(); print <<'EOF' ; <style type="text/css"> .Pope { font-weight: bold; color: #FF3010 !important; } .Apostle { font-weight: bold; color: #F84020 !important; } .Saint { font-weight: bold; color: #F44030 !important; } .Sage { font-weight: bold; color: #F04040 !important; } .Cardinal { font-weight: bold; color: #E04050 !important; } .Archbishop { font-weight: bold; color: #D04060 !important; } .Bishop { font-weight: bold; color: #C03070 !important; } .Chancellor { font-weight: bold; color: #B03080 !important; } .Canon { font-weight: bold; color: #A03090 !important; } .Abbot { font-weight: bold; color: #9030A0 !important; } .Monsignor { font-weight: bold; color: #8020B0 !important; } .Prior { font-weight: bold; color: #7020C0 !important; } .Parson { font-weight: bold; color: #6020D0 !important; } .Vicar { font-weight: bold; color: #5020E0 !important; } .Priest { font-weight: bold; color: #4010F0 !important; } .Curate { font-weight: bold; color: #3010FF !important; } .HighPriority { font-weight: bold; background-color: #FFFF00 !importan +t; } </style> <script type="text/javascript"> <!-- // "When a society has no colored pants to differentiate class... // ...it's a society without purpose" -- Wef // http://en.wikipedia.org/wiki/Kin-dza-dza! var SaintsBook = new Object(); EOF dump_saints($tree); print <<'EOF' ; function Colorize() { var links = document.links; for( var i=links.length-1; i>=0 ; --i ) if ( /\?node_id=(\d+)$/.test(links[i].href) && SaintsBook[RegE +xp.$1] ) links[i].className = SaintsBook[RegExp.$1]; } setTimeout('Colorize()', 600); // --> </script> EOF sub dump_saints { my $element = shift; if($element->tag() eq 'table') { my @contents = $element->content_list; if(@contents > 10) { # The saints table has lots of rows my %saints; shift(@contents); # The first row is headers foreach my $row (@contents) { my ($id) = (((($row->content_list())[1]->content_list( +))[0]->content_list())[0]->attr('href') =~ m/=(.*)/); my ($level) = ((($row->content_list())[3]->content_lis +t())[0] =~ m/([^ ]*)/); push(@{$saints{$level}}, $id); } foreach my $level (keys %saints) { print "var $level = [" . join(',',@{$saints{$level}}) +. "];\nfor( var i=$level.length-1; i>=0; i--) SaintsBook[$level\[i]] += '$level';\n\n"; } } } foreach my $e ($element->content_list()) { if(ref($e) and $e->isa('HTML::Element')) { dump_saints($e); } } }