Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Perl v5.18's sort understand lexical subroutines?

This is fixed in Perl v5.22.


Does Perl v5.18's lexical subroutines with sort? I finally had a use for them today where I had a complicated sorting routine that depends on the current position in the data structure to look at deeper parts.

Here's a small program:

use v5.18;
use feature qw(lexical_subs);
no warnings qw(experimental::lexical_subs);

my sub by_numbers { $a <=> $b }

my @sorted = sort by_numbers qw( 4 8 2 3 0 5 7 6 1 9 );

say "sorted: @sorted";

Apparently sort knows nothing about this because it is still looking in %main:: for the named subroutine:

% perl5.18.2 test.pl
Undefined sort subroutine "main::by_numbers" called at test.pl line 7.

% perl5.20.1 test.pl
Undefined sort subroutine "main::by_numbers" called at test.pl line 7.

I'm a bit disappointed because this is the first use case that rjbs uses in lexical subroutines in perl 5.


This part doesn't matter because I looked at the current version of the test instead of the v5.18 version.

I look it t/op/lexsub.t in the perl source, I find three tests that involve sort. They fail when run in isolation, and differ in a major way: there's a defined subroutine of the same name in the symbol table (as rjbs notes, these tests come from the current source and were not present in the affected stable releases.):

use v5.18;
use feature qw(lexical_subs);
no warnings qw(experimental::lexical_subs);

use Test::More;

sub _cmp { $a cmp $b }
sub bar::_cmp { $b cmp $a }
{
  package bar;
  our sub _cmp;
  package main;
  is join(" ", sort _cmp split //, 'oursub'), 'u u s r o b', 'sort our_sub'
}


{
  state sub _cmp { $b cmp $a }
  is join(" ", sort _cmp split //, 'lexsub'), 'x u s l e b',
    'sort state_sub LIST'
}

{
  my sub _cmp { $b cmp $a }
  is join(" ", sort _cmp split //, 'lexsub'), 'x u s l e b',
    'sort my_sub LIST'
}

sort completely ignores the lexical subroutines in all cases (for perls v5.18 and v5.20):

not ok 1 - sort our_sub
#   Failed test 'sort our_sub'
#   at test.pl line 29.
#          got: 'b o r s u u'
#     expected: 'u u s r o b'
not ok 2 - sort state_sub LIST
#   Failed test 'sort state_sub LIST'
#   at test.pl line 35.
#          got: 'b e l s u x'
#     expected: 'x u s l e b'
not ok 3 - sort my_sub LIST
#   Failed test 'sort my_sub LIST'
#   at test.pl line 41.
#          got: 'b e l s u x'
#     expected: 'x u s l e b'
# Tests were run but no plan was declared and done_testing() was not seen.

Besides this testing being problematic since it fails to isolate the environment, it's also tough to tell what the tester is doing and how much of the previous, far away setup each test demands. The tests themselves are lightly documented, if at all.


back to stuff mattering

Am I missing something here? It seems this never worked. The trick then, is what in the test file allows it to pass?

Please don't suggest workarounds. That's not why I'm asking.

like image 291
brian d foy Avatar asked Jan 13 '15 02:01

brian d foy


1 Answers

I'd like to say that this was working in v5.17.x and then got broken, but it looks like everyone missed it, and I missed even verifying that it worked. So… it doesn't. Or, much more happily, it didn't. This was fixed in:

commit 2872f91877d2b05fa39d7cd030f43cd2ebc6b046
Author: Father Chrysostomos <[email protected]>
Date:   Tue Sep 16 13:10:38 2014 -0700

    Make sort bareword respect lexical subs

—something I completely missed when implementing them.

…and since v5.21.4, this has worked as expected and promised.

like image 153
rjbs Avatar answered Oct 25 '22 17:10

rjbs