External Issue: Confusing sort behavior when comparator defines duplicate methods due to canResolveMethod behavior

20279, "ghbrown", "Confusing sort behavior when comparator defines duplicate methods due to canResolveMethod behavior", "2022-07-20T19:29:42Z"

Summary of Problem

The sort module can exhibit some confusing (to users) behavior if the comparator has multiply defined methods. For example, in the code below, when the compare method is only defined once, the sort uses compare. However, if the comment inside sort_wrap is removed then compare is defined twice, but the sort uses keyPart instead of compare.
This was extremely puzzling at first. I expected that I would either get an error for the multiple definition of compare, or I would be able to "overwrite" it and the second compare would be used.

@mppf and @bradcray found the cause of the behavior, the use of the reflection method Reflection.canResolveMethod in the sort module. When the method in question can't be resolved (like when there are multiple definitions) it silently falls back to another comparison method without warning or error.

We've talked about this in the Discourse thread (long, touches on multiple unrelated issues) and thought this issue could be a place to discuss similar problems, as well as possible "fixes" to this somewhat rare edge case.

I'm copying over a couple of Brad's thoughts from the thread:

Maybe the approach would be to have the sort module do something before falling back like seeing whether there are any methods named '.key' or seeing how many candidates there are for the call and issuing an error if there are more than one. Or maybe canResolve() needs to be redesigned in some way [maybe to give more information].

Steps to Reproduce

use Sort;

record comparator_def {
  proc keyPart(a,i) {
    writeln('keyPart');
    return defaultComparator.keyPart(a,i);
  };
}

proc sort_wrap(Data : [?Dom] ?eltType) {
  proc comparator_def.compare(a,b) {
    writeln('compare 1');
    if (a > b) {
      return 1;
    } else if (a == b) {
      return 0;
    } else {
      return -1;
    }
  }
  //proc comparator_def.compare(a,b) {
  //  writeln('compare 2');
  //  if (a > b) {
  //    return 1;
  //  } else if (a == b) {
  //    return 0;
  //  } else {
  //    return -1;
  //  }
  //}
  sort(Data,comparator=new comparator_def());
}

var a = [1,1,20,4,-5,2,3,111,12,5,100];
sort_wrap(a);
writeln(a);

Compile command:
chpl

Configuration Information

using packaged version on Arch Linux

chpl version 1.28.0 pre-release (c95e180325)
built with LLVM version 14.0.6