3

I asked a question about the use of "$a" and "$b" in Perl's sort() function the other day:

What exactly are "$a" and "$b" in Perl's "sort()" function?

I now have a follow up question. Are "$a" and "$b" only used by sort() or is there any other Perl function that takes advantage of these special global variables?

Or even if no other function uses them, are there any situations outside of sort() that you would use "$a" or "$b"?

Edit:

To clarify:

In short, the question is can "$a" and "$b" be used by something other than sort()?

I am just curious to see what other situations they can be used in. I have never seen "$a" or "$b" used by anything else and was wondering have any other special use outside of sort().

Community
  • 1
  • 1
tjwrona1992
  • 7,723
  • 5
  • 26
  • 76
  • they're not global variables. they're just defacto standard names for the arguments passed into a sort function's callback. – Marc B Oct 01 '14 at 14:04
  • 7
    @MarcB: the sort function's callback doesn't get passed anything (unless it has a `$$` prototype, in which case it uses `$_[0]` and `$_[1]` and *not* `$a` and `$b`). They are indeed (package) global variables. – ysth Oct 01 '14 at 14:10
  • something funny: `my ($a, $b); print Dumper [ sort { $a <=> $b } map rand(10), 0..9 ]` – salva Oct 01 '14 at 14:27
  • @salva `Can't use "my $a" in sort comparison` is funny? – TLP Oct 01 '14 at 14:29
  • yes, it is just `warnings` (and `strict`) that removes all the fun from perl! – salva Oct 01 '14 at 14:34
  • @salva I disagree. And that is not a warning that comes from `strict`or `warnings`. – TLP Oct 01 '14 at 15:03
  • @TLP: so, where does it comes from? – salva Oct 01 '14 at 15:08
  • @salva I just confirmed that even without `strict` or `warnings` the error still occurs. I don't know where the error comes from, but it definitely is not from `strict` or `warnings`. – tjwrona1992 Oct 01 '14 at 15:39
  • @tjwrona1992: Not in my perl! `$ perl -MData::Dumper -E 'my ($a, $b); print Dumper [ sort { $a <=> $b } map rand(10), 0..9 ]` – salva Oct 01 '14 at 15:41
  • @salva Hmm that is strange, it could be a difference in Perl versions. What version of Perl are you running? I am running v5.16.3. – tjwrona1992 Oct 01 '14 at 16:23
  • @tjwrona1992: 5.20.0 (Ubuntu 14.10) – salva Oct 01 '14 at 19:07
  • @tjwrona1992: It seems it was a bug that become fixed on 5.18.0... so, doubly funny! – salva Oct 02 '14 at 07:56
  • @salva: Hmm, very interesting. I wonder what would happen if you tried to declare $a and $b as lexicals in the scope of a `sort` without using `warnings` or `strict`. Would it clobber your locally defined $a and $b, or would it preserve them and restore their values when the `sort` completes? – tjwrona1992 Oct 02 '14 at 12:05

4 Answers4

6

can "$a" and "$b" be used by something other than sort()?

As it has already been explained, there's nothing special about $a and $b (except that they are predeclared). Asking if an ordinary variable can be used by some thing other than one function makes no sense. Here is $a being used by something that isn't sort:

 $ perl -E'$a=123; say $a;'
 123

That said, it's not a very good idea to do so. It's best to use lexical variables, and declaring $a or $b as lexical variables will render them unavailable to use in sort (or in List::Util's functions) without an overriding our ($a,$b);.

$ perl -e'sub foo { my ($a) = @_; "..."; sort { $a cmp $b } @a; "..." }'
Can't use "my $a" in sort comparison at -e line 1.
Community
  • 1
  • 1
ikegami
  • 322,729
  • 15
  • 228
  • 466
2

Other non-built-in functions, such as List::Util::reduce, use them too.

Could you explain why you are asking, though? I feel like you are looking for something bigger than that as an answer.

ysth
  • 88,068
  • 5
  • 112
  • 203
1

$a and $b are the names the sort function assigns to the two elements it is comparing, which are the parameters it assigns to the "compare()" user-supplied callback function.

You can think using the "$a", "$b" logic in any function you design, to which you provide a function as a parameter, and provide two (or more) arguments to that function...

Hope I was clear enough...

MarcoS
  • 15,673
  • 23
  • 78
  • 152
1

The short answer is "no, they're not special except in the context of sort". However, I did have occasion to use them outside of a sort routine recently, which is kind of germane to your question.

I used $a and $b directly in order to utilize my sort function for a single comparison. I scoped them with local and used a do block to contain the scope:

my $cmp = do {
    local $a = $summary->{current_version};
    local $b = $latest_version_on_usb;
    cmp_version();
};

cmp_version is a subroutine designed to be used with sort, so, normally its use looks like this:

my @sorted_versions = sort cmp_version @old_versions;

Because cmp_version knows it will be called by sort, it does all of its work on $a and $b internally.

The fact that I wanted to re-use my sort subroutine in a non-sorting context (I just wanted the output of a single "$foo cmp_version $bar" comparison as if cmp_version was a real operator like <=> or cmp ) is what prompted this. It's the only reason I can think of to use $a and $b unless it's in a sort block or subroutine--the fact that they are special in the context of sort means that messing around with them outside that context could end up biting you.

msouth
  • 716
  • 7
  • 21
  • Very interesting use of `$a` and `$b`. However in this situation if `$foo` and `$bar` are objects, I feel like it would make more sense to simply overload the `<=>` operator to compare versions, that way you could directly use `<=>` like so: `$foo <=> $bar` and get the results you're looking for. – tjwrona1992 Feb 06 '17 at 21:11
  • 1
    @tjwrona1992 That would be a great way to go, in that case. In mine, as it happens, they're just hashes with version information--$foo->{major}, $foo->{minor}, $foo->{update}, and $foo->{rc}. I needed a special sort because 1.0.0 is actually *after* 1.0.0rc10--you do several release candidates before deciding "this is the actual 1.0.0". Kind of a weird case, and I guess it made sense that it generated a weird code situation :). – msouth Feb 07 '17 at 00:06
  • In that case, if you want to get really fancy you could make the hashes store version objects instead of simple strings and the version class could have `<=>` overloaded! Then you could compare `$foo->{major} <=> $bar->{major}`. :) – tjwrona1992 Feb 07 '17 at 13:39