Woah! Thank you for taking the time to explain your perspective and thoughts! It's a lot of food for thought. I wish I had the background and knowledge to discuss things on equal footing :(
Just a few additional questions/comments:
> Specifically, Haskell, the language as defined, achieves ad-hoc polymorphism by passing a dictionary parameter to functions using overloaded function names. This is done using the standard terms in Haskell and has a clear denotaional semantics for such terms. Rust usage of traits is talked about and reasoned about as a more primitive part of the language, not just a pretty piece of sugar with a more basic existence in the formally defined core of a programming language.
Would it be accurate to say that Swift's non-monomorphized generics are more along the lines of the Haskell approach you prefer (i.e., single function implementation with a separate parameter for additional type info)?
And a bit more hand-wavey, but IIRC Rust's generics were defined in such a way that monomorphization is technically an implementation detail; in other words, I want to say a Haskell-like approach isn't strictly ruled out. I'd take that with a large grain of salt, though.
> If ad-hoc polymorphism is something a language designer wants to incorporate into the usage of a language, my position is that defining a typeclass style sugar over a clearly defined set of terms in the core, formally defined language would be at least a method of prohibiting issues with the resolution, definition, and various methods of implementation of ad-hoc polymorphism polluting the syntax and semantics of the language itself. But the above requires a firm definitional boundary between what is the language and what is syntactic sugar to be built into the definition of the language and built into the compiler infrastructure.
Might MiniRust [0] be something along the lines of what you would desire? It seems to fit the general idea of a smaller formally-specified "core" language. There's also this bit about traits specificlaly from the readme:
> That translation [from Rust to MiniRust] does a lot of work; for example, traits and pattern matching are basically gone on the level of MiniRust.
Swift is a good reference point in this area because Swift essentially took the dictionary-passing approach of Haskell and added the ‘low level’ type information like bit-width, offsets, etc as a Type Metadata parameter. The big upside is that Swift gets a good deal of performance boost compared to Haskell and other languages that have uniform datatypes (boxed values). So to extend the concept I was describing from Haskell to Swift would be creating concrete syntax for the language, which has no semantic identity outside those already existing in the semantics of Witness Tables. Sometimes the term “derived form” is used to talk about syntax like this. It is the term for concrete syntactic forms that are only defined in terms of syntax forms in the base/core language. It is, for the most part, correct to view derived forms as macros or as a more general metaprogramming construct, but but in Haskell’s case the macros are implemented in the compiler and expanded in a particular phase of compilation.
Swift is also good touch point for considering what the compiler does with the actual implementation of ad-hoc polymorphism. Swift is optimizing to monomorphized instances of a generic function give some heuristics about expect performance gains by specializing the function for a given type (Haskell also does this in GHC, but still pays a performance price for using boxed values).
So to answer the question: the part of Haskell’s implementation of typeclasses that I think is the correct method is that it is merely a derived syntactic form that is expanded by the compiler into Haskell’s actual language (its abstract syntax as encoded as ghc-core in GHC in particular). From this perspective Swift doesn’t provide the derived form, it just provides the implementation directly for developers to use omitting the sugar that Haskell provides. I tend towards explicitness as a strong default in language design.
Rust doesn’t have a formal semantics currently, so they could certainly adopt a derived form approach to traits, but I don’t know enough Rust to be able to determine what issues existing thoughts, assumptions, and type theory ‘commitments’ would act as obstacles to such a semantic.
As to MiniRust, Ralf Jung (at ETH Zurich) has done some excellent work, along with some of his students (Max Vistrup’s recent paper on Logics a la Carte is very, very good). MiniRust does attempt to be comparable to Haskell’s GHC-core. So in the sense of being or approaching what I would view as the (excluding type theory based options) correct way to implement ad/hoc polymorphism, yes, to sum: MiniRust as the semantic definition of a derived syntactic form and a compilation phase for ‘expansion’ of the trait macro.
Those explanations aside, my issues with ad-hoc polymorphism do not go away under this implementation, I’m generally opposed to generic functions (especially function name overloading). But I think that if a language is pursuing ad-hoc polymorphism as a feature they should pursue it in a well founded and formal manner.