develooper Front page | perl.perl5.porters | Postings from August 2016

Re: [perl #128786] making $^V a version object broke functionality

Thread Previous | Thread Next
From:
Lukas Mai
Date:
August 3, 2016 19:49
Subject:
Re: [perl #128786] making $^V a version object broke functionality
Message ID:
aa376a9b-eaf0-bcb9-2133-9646f1f0764d@gmail.com
Am 03.08.2016 um 12:39 schrieb John Peacock:
> On 07/31/2016 03:46 PM, Lukas Mai wrote:
>> Am 31.07.2016 um 17:48 schrieb John Peacock:
>>> So your code could be rewritten as:
>>>
>>>    printf "use feature ':%d.$d;\n", @{$^V->{version}}[0,1];
>>
>> That's not part of the public API. I'd have to rely on implementation
>> details that might change at any time.
>
> Actually, the internal representation *is* part of the public API, see
> version::Internals.

Wait, version::Internals is supposed to be a public API?

You definitely need to document that, then. When something is called 
"internals", I assume it's purely informational and describes a snapshot 
(the current state of the implementation) with no guarantees about 
stability or compatibility.

Case in point: the $v->{version} field is described in a document called 
"version::Internals", in the section "IMPLEMENTATION DETAILS", in the 
subsection "Version Object Internals", and labeled "[t]he internal 
structure of version objects".

All of this screams "DO NOT USE" (outside of debugging) to me.

> The version.pm code is also specifically designed
> to be easy to subclass, so you would be free to implement your own
> method calls to do whatever you want (like generating a v-string form).

Again, this should be documented, then. Neither version nor 
version::Internals say anything about subclasses, base classes, or 
inheritance.

(Besides, I'd have to rebless $^V, which is a whole nother can of worms.)

>> 2. No special treatment is required for comparing v-strings. v-string
>> comparison is normal string comparison.
>
> While this is true, it is also misleading, in that you had to already
> know you were dealing with a v-string to construct your test.  Most
> people found this confusing and used $] instead, which has its own set
> of problems.

I find the current situation even more confusing. "v-strings are just 
arrays of codepoints" was simple and made sense to me. (I wouldn't be 
surprised if people still mostly used $] because it's just a number - no 
surprises with overloading.)

>> 3. Special treatment is required for comparing version objects. version
>> object comparison is not normal string comparison, and inadvertently
>> stringifying a version object and then comparing it leads to wrong
>> results.
>
> Then frankly you are using the version module wrong.  A version object
> can be trivially compared against either a
> string-that-looks-like-a-version, a bare number, or another
> version-derived object using either numeric or string comparison
> operators (> and gt).  If you force stringification, of course you lose
> the object methods.

I'm not using the version module (directly). I'm using the $^V variable, 
which used to be a string (it was when I learned Perl) so it made no 
difference whether I used $^V or "$^V".

A few days ago I had to (for the first time) do something with perl 
versions that wasn't just a simple inequality check, for which I'd've 
used $]. So this was how I ended up looking into how $^V actually works 
nowadays. (I realize I'm about 10 years late with my complaints.)

>> 4. Pretty-printing a version number is rare in my code. Most of the time
>> I only want to compare versions, extract components, and construct new
>> versions (e.g. for automatically incrementing a version number, etc).
>
> The fact that the normal stringification method of version objects is to
> print in a consistent normal form is just gravy.  The real reason they
> exist in the first place is to treat versions as first class objects,
> with consistent behavior.  To be honest, you are the first person to
> request being able extract the elements of the version for further
> processing.  Most people appear to want to treat versions as fixed values.

($] works fine for fixed values. Why bother with an object then?)

My actual use case is this: I have a project (stored in a single 
repository) that I want to be able to run under different perl versions. 
There's a module (pdflib) that's specific to the perl version, i.e. 
different perls require different versions of the module.

My solution was to create a wrapper module that adds a version-dependent 
subdirectory to @INC, then loads the real module. That way all variants 
of the module can be added to the repository together, and perl 
automatically selects the right variant at execution time.

Further constraints: I want the subdirectory names to look nice for 
human readers (i.e. no "5.018002" or similar), and the minor version 
should be dropped because only the major version of perl5 matters. I 
went with "v5.12", "v5.14", etc. (Accidental bonus: The '.' means I 
can't accidentally load a module from this subdirectory via 'use 
v5_12::whatever' because no bareword can contain '.'.)

A while later I came across a second use case: Create a dynamic script 
template (e.g. for use with vim) that automatically inserts 'use feature 
":5.XX";' at the top of new files, where 5.XX is the version of the 
current perl.

Both of these are easy with v-strings: sprintf('v%vd', substr($v, 0, 2)) 
and sprintf('use feature ":%vd";', substr($v, 0, 2)), respectively.

>> In that case a method to return the numeric components would be nice, as
>> well as a method to get the v-string representation:
>>
>>     my @parts = $^V->parts;    # (5, 24, 0)
>>     my $str   = $^V->vstring;  # "\x05\x18\x00"
>>
>> Would that be good addition to the version.pm API?
>
> Attached is a proposed addition to the public API that provides the
> elements() method to return the array ref, as well as helper functions
> to print out the epoch/major/minor/patch for any given version object
> (including $^V).  Since this has to replace the internal Perl
> implementation of version.pm with the additional methods, you would have
> to include
>
>   use version;
>
> before you can use any of these methods.  If this would fit your needs,
> I'd be happy to release a new version.pm to CPAN and this functionality
> would be included in any new Perl releases.

You seem to have a (harmless) off-by-one error in there: You do 'push 
@elements, 0 while $#elements < 2' (which ensures @elements has at least 
3 elements) but then you only access $elements[0] and $elements[1], as 
if the condition had been '... while @elements < 2'.

The other issue I see is that the methods and names are specific to $^V, 
i.e. the way perl uses its version numbers. They're not necessarily 
right for a generic version object.

Finally, the epoch/major/minor/patch methods form yet another 
pretty-printing API, which version.pm already has. (The 'major' method 
happens to fit my first use case exactly, but doesn't help with the 
other one ('use feature').) I'd rather have the building blocks to make 
my own pretty-printer.

I like 'elements' but from the name I would've expected it to return a 
list, not a reference to an array.

-- 
Lukas Mai <plokinom@gmail.com>

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About