Ian, thanks for taking the time to read and respond to my post. On Sun, Aug 9, 2020 at 6:29 PM Ian Lance Taylor <i...@golang.org> wrote: > If we accept this argument, then in Go it wouldn't be appropriate to > write a single function that works on both builtin and user-defined > types.
This I disagree with; what you regard as inappropriate, I see as a desirable goal. The question is whether there is a reasonable way to achieve it, one for which the benefits outweigh the costs. Before I explain why I disagree, let me mention that sorting was perhaps not the best example for me to have used. It is very common to sort things in an order different than the default (e.g. integers in reverse order), or to sort things that don't have a default order (e.g. countries by area, population, or date of formation). For this reason, sort functions in any language very often accept a comparison function. A better example might be a function that finds the roots of a polynomial with real-valued coefficients, where the coefficients are taken from a type F that might be float32, float64, or a user-defined type such as one based on big.Float. In this function, we want to use the default arithmetic operations provided by F. It would be very unusual to override those with a different choice of operations. But in the type lists approach, unless we write two distinct versions of the function, we must use an adaptor type or object (or multiple adaptor functions) to indicate to the function what arithmetic operations to use. There is no way for the function to access these operations otherwise (except reflection). > I think this is open to question. In C++, for example, std::sort > takes an optional comparison class. In effect, the default if no > comparison class is provided is to use operator<. That is a > reasonable and appropriate choice for C++. But Go does not have > function overloading and does not have default values for arguments > (https://golang.org/doc/faq#overloading). So the natural way to write > a sort function is to provide a comparison function. That Go does not have default argument values is, I think, merely a distraction. This is easily handled with multiple functions; one would like to write func SortBy[type T](s []T, less func(T, T) bool) { ... } func Sort[type T ...](s []T) { SortBy(s, the_natural_order_on_T) } where the constraint on T in Sort expresses that T must have a natural ordering. > If we accept this argument, then in Go it wouldn't be appropriate to > write a single function that works on both builtin and user-defined > types. Writing such a function would be relying on some sort of > default comparison function, which is not the typical Go approach. But Go does have a default comparison for builtin types - the < operator. This is used by sort.Ints, sort.Float64s, and sort.Strings. With generics and type lists, it will be possible to combine these into a single function that also works on other builtin types. One can also give a user-defined type a default comparison, by supplying a Less method (or Cmp, as in big.Int). The difficulty is that without generics, there is no way to write a function specification requiring the presence of such a method. Generics with type lists simplify both of these cases, but do not give us a way to unify them. Another example - the String method of a type describes the default way of displaying the type's values in text. For types with no String method, there is a default builtin way. And displaying values as text is so very useful that Go already provides a family of functions to do this, and that work on both types with a String method and types without String. This is the fmt package, and it uses reflection internally to achieve this. Try to imagine writing printing code if fmt.Print were replaced by these two functions: // Prints values in a fixed builtin way, ignoring any String method that might exist. func PrintB(a... interface{}) { ... } type Stringer interface { String() string } func PrintS(a... Stringer) { ... } Or if fmt.Print became: func Print[type T](func tostring(T) string, a ...T) I think you will agree that it would be quite a bit more awkward than with the existing fmt.Print. > If we accept this argument, then in Go it wouldn't be appropriate to > write a single function that works on both builtin and user-defined > types. And I must reply - not only is it appropriate, it is already done in one of the most widely used packages in the standard library. The question is, is there a reasonable way to make this easier in other cases? -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAADvV_sAfd%2Bx-Wu9WBP_2gGxJZcYX2acsAg4_w71Z5shebhvCA%40mail.gmail.com.