Why do I need a second Function in SortBy for Association?

I cannot understand why I need a second pure function when trying to sort Association by Key. Here is an example

data=
<|{10, mvDownUp[{1, 4}, {}]} -> 1/4,
{41, mvDownUp[{4, 6}, {}]} -> -1/4,
{8, mvDownUp[{1, 2, 3}, {}]} -> -1/4,
{39, mvDownUp[{2, 3, 6}, {}]} -> -1/4|>


I want it to sort by key, i.e.

SortBy[data, (Key[#] &) &]

(* <|{8, mvDownUp[{1, 2, 3}, {}]} -> -1/4,
{10, mvDownUp[{1, 4}, {}]} -> 1/4,
{39, mvDownUp[{2, 3, 6}, {}]} -> -1/4,
{41, mvDownUp[{4, 6}, {}]} -> -1/4|> *)


Why the second pure function? (Mathematica version 10.3)

• Who said you need it? It is a coincidence, and as good as SortBy[whatever &]. Better check KeySort. – Kuba May 30 '18 at 7:39

As Kuba mentioned in the comments, it's coincidence that the two layered function works -- it turns out that function is equivalent to Null &. You can check this by running:

Reap[SortBy[data, ((Sow[Key[#]]) &) &]]


Which will output a list containing firstly the sorted list, and secondly the list generated by the function used to sort it. In this case, that second list is {}.

It turns out that by itself, Key[#] & also doesn't mean anything, but it has very different sorting characteristics. You can see that by omitting the outermost function above:

Reap[SortBy[data, (Sow[Key[#]]) &]]


The second part of this output is:

{Key[1/4], Key[-1/4], Key[-1/4], Key[-1/4]}

Which correlates with the first element getting moved to the end in the "sorted" result. However, this is actually the same as SortBy[data, #&].

In short, with associations it appears that SortBy sorts by the function given to it first, and then by key to resolve conflicts. As such, any function that generates the same output for every member of the association should be the same as sorting by key. Perhaps counter-intuitively however, Key[#]& absolutely does not produce the same result for every element and also doesn't produce the keys of the elements.