in reply to Fun with complex sorting on arbitrary criteria list.

First a debugging tip with eval and dynamically created code. It is really helpful if you have the generated code displayed in error messages. Otherwise bad input can crash your code, but it can be hard to figure out why. Similarly I like using line directives as described at the bottom of perlsyn so that warnings come with nice descriptive messages about where the eval is in my code, rather than knowing that the error was at line 2 of eval 14. (merlyn showed me this trick.)

Also I don't like using autodetection of datatypes like you have above. My experience is that real-world data often throws you surprises like a field with mixed numbers and strings in it. I've run int that too often to trust code which will break on that case. (Although tye has a cute sprintf trick at Re: Sorting on Section Numbers which is acceptable with many datasets.)

That said, I have tackled this exact problem with closures. With something like this (untested):

# Take a list of sort functions, return a sort function # that tests them in order, with short circuit logic. sub ret_combined_sort_func { if (1 == @_) { return shift; } else { my @subs = @_; return sub { my $ret = 0; foreach (@subs) { $ret = $_->(); return $ret if $ret; } # I guess we're "out of sorts" :-) return 0; } } }
And now you can process the conditions, for each condition that you see, adding another subroutine to a list of known sort conditions. And then combine them as above to get a single sort function suitable for sticking in a sort. This part is straightforward if a bit tedious to write. (The main problem is settling on the format of the data structure that says which fields to sort in which directions.)

A note to people who like to generalize. I implicitly assume above that the sort functions are defined in the same package that sort will be called in. Or at least know the package. That is because the $a and $b that is set depends where sort is called, so the sort function had better look there. If you don't want to avoid that then you need to modify the closures to all use a ($$) prototype. sort will in recent (5.6 on up) versions of Perl then pass in the two scalars to compare rather than alias them in $a and $b. Now your sort functions can be defined in a different package than sort is eventually called in. (I thought that this was pointed out to me by dws. He doesn't remember that, and I can't find where it was pointed out. I've had several occasions to use it since though.)

Update: dws pointed out a piece of mangled grammar, and told me that he didn't remember telling me about using prototypes in a sort.

Update 2: "lease" should have been "least". Fixed.