What does the default TArray.Sort comparator actually do and when would you use it?

delphi, delphi-xe2

Solution

The default comparer provides implementations for many common types. Specifically it supports the following:

- Integral types: `Byte`, `Word`, `Integer` etc.

- Enumerated types.

- Floating point types.

- Strings.

- Sets.

- Class instances.

- Procedural variables.

- Methods.

- Variants.

- Static arrays.

- Dynamic arrays.

- Interfaces.

- Pointers.

- Records.

For many of these types the default implementation is exactly what you would expect. For example, for integers, enumerated types, floating point types the implementation uses the `<`, `>` and `=` operators. For `string` the default implementation calls `CompareStr`.

For other types, the default implementation is probably less useful. For example, for records, the comparison is a bytewise binary compare. It's highly likely that you'd want to supply your own implementation of a comparer for a record. One thing to watch out for with records is that the default comparer will compare any padding in your record, and you never want to do that. So it is never useful for an aligned record that has padding. And I'd also question the utility for records that contain reference types.

For dynamic arrays, the default implementation compares length first, and then, if length is equal, compares the binary content of the array. So, that might be reasonable for arrays of simple value types. But for multi-dimensional dynamic arrays, or arrays of reference types, not so much.

For class instances, methods, procedural variables, interfaces the default comparer treats the operands as a pointer (two pointers in the case of methods) and performs an address comparison.

When you you want to use the default comparer? Well, you'd use it whenever it matches your requirements for a comparer. So it certainly makes sense for simple value types. Beyond that you'd need to decide on a case by case basis.

Problem

In Delphi XE2's help for `System.Generics.Collections.TArray.Sort`, it says ``` Note: If the Comparer parameter is provided, it is used to compare elements; otherwise the default comparator for the array elements is used. ``` I dug back a bit and found that the default comparator for `TArray.Sort` is `_LookupVtableInfo` from `System.Generics.Defaults`. The code for this is ``` function _LookupVtableInfo(intf: TDefaultGenericInterface; info: PTypeInfo; size: Integer): Pointer; var pinfo: PVtableInfo; begin if info <> nil then begin pinfo := @VtableInfo[intf, info^.Kind]; Result := pinfo^.Data; if ifSelector in pinfo^.Flags then Result := TTypeInfoSelector(Result)(info, size); if ifVariableSize in pinfo^.Flags then Result := MakeInstance(Result, size); end else begin case intf of giComparer: Result := Comparer_Selector_Binary(info, size); giEqualityComparer: Result := EqualityComparer_Selector_Binary(info, size); else System.Error(reRangeError); Result := nil; end; end; end; ``` It is called as ``` IComparer<T>(_LookupVtableInfo(giComparer, TypeInfo(T), SizeOf(T))) ``` I've looked through this quite a bit and I'm not really all that sure I know what it does. Does it just compare the bit in memory against each other or what exactly? Second part of the question is a more generalized one of what situations would you be likely to actually want to use the default comparator, or is it unlikely that you'd ever actually want to use it?

Original source