perlcoderef

passing a coderef to sort() problems


Using the following pieces of code, I get wildly different results.

$val{"ENOTE"} = 05;
$val{"WATCH"} = 10;

my %sortFunc = ();

my $sortFunc = sub {
    my ($va, $vb);

    $va = $val{$$a{"etype"} . ":" . $$a{"emsg"}} // $val{$$a{"etype"}};
    $vb = $val{$$b{"etype"} . ":" . $$b{"emsg"}} // $val{$$b{"etype"}};

    #    printf("$$a{etype} gets $va\n");

    $$a{"year"} <=> $$b{"year"}
    || $$a{"month"} <=> $$b{"month"}
    || $$a{"day"} <=> $$b{"day"}
    || $$a{"sym"} cmp $$b{"sym"}
    || $va <=> $vb;
};

$sortFunc{"date"} = sub {
    my ($va, $vb);

    $va = $val{$$a{"etype"} . ":" . $$a{"emsg"}} // $val{$$a{"etype"}};
    $vb = $val{$$b{"etype"} . ":" . $$b{"emsg"}} // $val{$$b{"etype"}};

    #    printf("$$a{etype} gets $va\n");

    $$a{"year"} <=> $$b{"year"}
    || $$a{"month"} <=> $$b{"month"}
    || $$a{"day"} <=> $$b{"day"}
    || $$a{"sym"} cmp $$b{"sym"}
    || $va <=> $vb;
};

When I call them, I get wildly different results.

@newsortrec = sort $sortFunc (@$rec);
@newsortrec = sort {$sortFunc{"date"}} (@$rec);

The call to $sortFunc works as I'd expect, and I have verified its output. The output from {$sortFunc{"date"}} is really odd. It's not gibberish like you'd expect if it had gotten bad data or ran bad code. It's just sorted in the wrong order. It's changed, and it's "sorted", but in a really weird way.

Is there something about the mysterious $a and $b that's giving me grief?

The fact that they are (foolishly) named $sortFunc shouldn't be a concern, should it? At least as far as perl is concerned.

Is there something different about the scoping rules for $a and $b?

I've diffed the code, so I know that it's the same.

Any hints/clues? I'm trying to move the code into the hash (where it runs... strangely).

Thanks.

-Erik


Solution

  • When using the sort BLOCK LIST calling convention, the block should return a value that indicates how $a compares to $b. However, your sort compare block returns a code ref ($sortFunc{"date"}). You might as well have used

     sort { 1 } @$rec;
    

    Replace

     sort { $sortFunc{date} } @$rec;
    

    with

     sort { $sortFunc{date}->() } @$rec;