That's exactly what C++ is doing for their template. The problem here is that if you want to use some generic functions, then you need to look into its implementation to see what kinds of requirements are needed for its type. And if you failed to meet the requirement, you'll very likely get several hundred lines of cryptic compiler error message; C++ compilers have been trying very hard to make the error message readable but it's still an awful experience. Also, an implementer now needs to be extra careful when they want to update the function since a single line of seemingly innocuous change may bring breakages for downstream users. Of course this can be prevented by carefully written exhaustive tests, but then what's the point of not having contract?
So the lessons from a number of PL implementations show that this kind of information needs to be explicitly encoded in codes, and that's the whole point of having "contract", "type class", "concept" or whatever else it's called. Compilers may be able to infer technical details of type, but at least for now it's not sophisticated enough to infer the original intention of the writer.
Sorry, still don't get it. Extra contract code needs to be written just to prevent "cryptic" compile-time errors? It's just a type mismatch/error like many others to me. Cryptic error messages can be made less confusing by improving the output.
Since Go doesn't have standalone object files / binary libraries, it's not going to produce confusing link-time errors for this.
The problem is you don't know if the error is in the type-parameter or if it's in the generic class. Take this very simple c++ program as example, it has 3 potential sources of error and it is not clear from the contract of the foo-function which one is the actual error.
In this particular case it's easy to deduce that something is misspelled and error 2 is the real error but the compiler is probably going to tell you it is error 1. And once you get into more complex programs the problem might be that the Bar class is not simply supported by the generic function or that the generic class is implemented incorrectly.
If you instead could add an interface constraint on T (like for example C#/Java/Typescript allows) it would be clear from the contract that this interface defines all the required functions on T if Bar doesn't implement those it is unambiguous that the implementation of the interface is not there.
> If you instead could add an interface constraint on T (like for example C#/Java/Typescript allows) it would be clear from the contract that this interface defines all the required functions on
Then you just have a 4th possible spot for an error. I don‘t see an essential difference between considering the function definition as the reference and having a contract (where typos are possible as well), just the latter being cumbersome and superfluous.
Assuming the interface definition is correct, it gives you one degree less of freedom. Error #1 is always evaluated vs the interface. Error #2 is also always evaluated vs the interface. Error #3 is evaluated vs the type constraint.
So each of the 3 potential errors can always be pinpointed exactly, as opposed to my example where it could be any 3 (or all 3 simultaneously) of them because "T having a hardToSpell-method" is not part of any public interface description, it's something deep in the implementation of the foo-function (in my example it's not very deep but in real code it usually is).
Typically you would have the template instantiated for multiple classes (…or there wouldn't be a need for templates). Each class will have its own definition of the functions used on the template argument. If the function definition is the reference, which one?
In this case the mismatch is between a type argument and the way that a type parameter is used, so it's not a type mismatch/error, it's a meta-type mismatch error. You are suggesting that the meta-type be inferred from the function (and any functions that it calls) rather than being explicitly stated. That is doable--C++ does it--but it means that the user has to understand the requirements of an implicitly inferred meta-type. The Go design draft suggests instead that the user be required to understand an explicitly stated contract.
As I mentioned, it's not just for avoiding cryptic error messages, though I am not sure if we're even referring the same thing as this is a completely different one from linker errors. Believe me, improving the output doesn't help that much. Hundreds of C++ compiler developer have been trying that for tens of years. None of them has succeed to the level of making a novice understands what's going on when they give sort(list) to the compiler.
To iterate my point, it serves as a "contract" between users and the code author. Without this, any user of a generic function will implicitly depend on its implementation, which creates tight coupling. Cryptic error messages or unintentional breakage are just undesired side effects from not having this clear boundary. So, the interface of generic functions needs to be explained to its users anyway; then why not making this understandable to compiler and prevent users from making such mistakes?
So the lessons from a number of PL implementations show that this kind of information needs to be explicitly encoded in codes, and that's the whole point of having "contract", "type class", "concept" or whatever else it's called. Compilers may be able to infer technical details of type, but at least for now it's not sophisticated enough to infer the original intention of the writer.