ttdsuen has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to do this,
package Foo; ... sub sort(&) { my $self = shift; my $code = \&{shift @_}; sort $code @{$self->{arrayref}}; } my $foo = Foo->new; ... $foo->sort({ lc($a) cmp lc($b) });
And it fails complaining some scope::$a,$b not defined (with my). The question is, how can I make this work? How can Perl's sort avoid this kind of problems? Daniel.

Replies are listed 'Best First'.
Re: relaying sort's code block
by ikegami (Patriarch) on Aug 18, 2014 at 22:21 UTC

    1) The code you posted doesn't exhibit the problem, and 2) the complaint is different that what you say it is.

    The problem is found in code of the following form:

    package Foo; sub sort($&) { my ($self, $cmp) = @_; ... my @sorted = sort $cmp @list; <-- sort compiled in one package ... } package Bar; Foo->sort({ $a cmp $b }); <-- Sub compiled in another

    sort sets $a and $b of the package in which the sort is present.

    The simplest solution (while continuing to use $a and $b) is

    package Foo; sub sort($&) { my ($self, $cmp) = @_; ... my $caller = caller; my @sorted = eval("package $caller; sort \$cmp \@list"); die $@ if $@; ... }
Re: relaying sort's code block
by tobyink (Canon) on Aug 18, 2014 at 22:15 UTC

    Try something like:

    package Foo; ... sub sort { my $self = shift; my $code = shift; sort { $code->($a, $b) } @{$self->{arrayref}}; } my $foo = Foo->new; $foo->sort(sub { lc($_[0]) cmp lc($_[1]) });

    I know it's not as pretty, but it should work.

    How does Perl's built-in sort manage to be prettier than code you've written yourself? The answer's in the question!

Re: relaying sort's code block
by Laurent_R (Canon) on Aug 19, 2014 at 06:47 UTC
    You've probably be given the solution, but just a couple of comments.

    Although it might work and this is unlikely to be the cause of your problem, I do not think that naming your own function or method with the name of a built-in function is very good practice. It might obscure any issue. An additional comment is why are you doing this:

    my $code = \&{shift @_};
    The argument should presumably be a sub ref. And, in the case of your code, it is (thanks to the prototype). So you could have simply:
    my $code = shift;