> > When is it important to not just express what operations are > required for a type, but also to try to rule out some types? >
I think the short answer is: numeric code. That's when one thinks about which types make sense for an algorithm, not just which operations. I'm not exactly sure why. It could be because Go doesn't support operator overloading. In C++ with concepts, maybe the concept for writing some generic math function wants operator+ and operator/, and no one cares that that may result in nonsense for some implementations of those operators. In Go 1, we write numeric code with specific types: float64 and not int64, for instance. Go insists on conversions between numeric types to keep us out of trouble: you can't call func Average(a, b float64) on ints without explicitly converting them. It seems natural to want to keep that precision and safety, but generalize it. In Go 1, if we wanted to write a numeric algorithm that worked on, say, two slices of floating-point numbers, we'd give it the signature func(x, y []float64). If later we wanted to support float32, we'd have to copy the code, or make the caller do an expensive conversion. The same problem would happen if the caller defined their own floating-point type (e.g. type MyFloat float64). I think I should be able to say, simply and clearly, that the slice element can be any type whose underlying type is float32 or float64. Furthermore, I don't want to specify the exact operations my implementation currently uses. I may want to change the code to use "-" instead of "+" later, for reasons of clarity or numerical stability. I shouldn't have to update the contract for that. contract(t T) { t = 0.0 } might seem to restrict to the types I want, but it doesn't; you can assign 0.0 to an integer type. contract(t T) { t = 0.5 } is wrong too. It includes complex types. contract(t T) { float64(t) } also works for ints, so no good. I believe the answer is contract(t T) { t = 0.5; float64(t) } but I'm not positive about that. Certainly, very few people who read that will immediately understand that T is a type whose underlying type is a float. (And I haven't done the second part, where I add all the valid operators for floats.) Earlier you wrote > [T]o me it always seems quite clear which type arguments a contract allows and excludes. It's exactly the set of types that type check successfully. It's true that sometimes this can be a surprising type, but to me that seems just like the fact that it can be surprising which types implement an interface. I think this example, and the other ones given in this thread, demonstrate that this is not "just like" the surprise of which types implement an interface. It's more like solving a puzzle, as someone (Axel?) has said. -- 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. For more options, visit https://groups.google.com/d/optout.