3 ms·
Arguably, that doesn't count as type classes because it REQUIRES call-site awareness of the implementation. This makes it fully ad-hoc and fully impractical as
by haimez 10y ago
Arguably, that doesn't count as type classes because it REQUIRES call-site awareness of the implementation. This makes it fully ad-hoc and fully impractical as a useful abstraction.
At that point you might as well call a static method without polymorphic parameter types, because it's just as (in)convenient and 100% more readable to the developer maintaining the project after you move on to a better programming language.
- louthy 10y ago> Arguably, that doesn't count as type classes because it REQUIRES call-site awareness of the implementation Yes. I should have stated it's not real type-classes, but it is real ad-hoc polymorphism, which does get you much of the way there. The type-system won't infer the instance, you need to specify it manually. That doesn't make the solution less powerful from a generic programming point-of-view (if anything it makes it more powerful, because you can provide the instance you want to use); however it does make it more awkward to use. > and fully impractical as a useful abstraction. I disagree with this though. Finally being able to define a numeric type, or make types into real monads where a function can declare a constraint that requires an argument to be a monad is a good thing. > At that point you might as well call a static method without polymorphic parameter types From what I can tell, you're thinking of just the call site, but a whole call stack can carry through the constraint, and therefore the call site doesn't need the concrete implementation, it just needs a type that is constrained to the 'type class' (interface). The call site wouldn't know the type of the static method to call in your case. For example with a numeric type: public static T Add<T>(T lhs, T rhs) => // what static method can you call here? If you don't use polymorphic types, then you're not writing generic code, which is what this is for: public static class Math { public int Add(int lhs, int rhs) => lhs + rhs; public double Add(double lhs, double rhs) => lhs + rhs; public float Add(float lhs, float rhs) => lhs + rhs; public decimal Add(decimal lhs, decimal rhs) => lhs + rhs; } What about when you forget: BigInteger, short, byte, long, etc. But with the method I explained above: public interface Num<A> { A Add(A lhs, A rhs); } public struct NumInt : Num<int> { public int Add(int lhs, int rhs) => lhs + rhs; } public struct NumBigInt : Num<BigInteger> { public BigInteger Add(BigInteger lhs, BigInteger rhs) => lhs + rhs; } etc. Any code that works with numeric values can then be written once. I'm sure many C# programmers over the years have cursed over having to write N variants of something that should work with IArithmetic, or INumber, or something similar. This gets around that problem (and without causing any boxing either). So, personally, I think it has value. Even if it's only needed rarely. > because it's just as (in)convenient and 100% more readable to the developer maintaining the project after you move on to a better programming language. My library isn't about the mindset of programmers who are stuck in OO-land with all the conservative nonsense that goes along with it. So although I agree there's a learning curve, I don't think this is too problematic for those who want to write truly generic code. By the way, Microsoft are experimenting with this technique[1] (and new grammar) for future versions of C#. Whether it makes it or not, who knows, but I think it would be a super valuable feature for C#. [1] https://github.com/CaptainHayashi/roslyn/blob/master/concepts/docs/concepts.md https://github.com/CaptainHayashi/roslyn/blob/master/concept...