▲ | PaulHoule 2 days ago | ||||||||||||||||||||||||||||
I haven't written C# professionally since the early 2010s but back then the language had a big problem in that the old Container classes were not compatible with the Container<X> classes that were added when they added generics to C#. This created an ugly split in the ecosystem because if you were using Container<X> you could not pass it to an old API that expected a Container. Java on the other hand had an implementation of generics that made Container<X> just a Container so you could mix your old containers with generic containers. Now Java's approach used type erasure and had some limitations, but the C# incompatibility made me suffer every day, that's the cultural difference between Java and a lot of other languages. It's funny because when I am coding Java and thinking just about Java I really enjoy the type system and rarely feel myself limited by type erasure and when I do I can unerase types easily by - statically subclassing GenericType<X> to GenericType<ConcreteClass> - dynamically by adding a type argument to the constructor - mangling names (say you're writing out stubs to generate code to call a library, you can't use polymorphism to differentiate between
and
since after erasure the signature is the same so you just gotta grit your teeth and mangle the method names)but whenever I spend some time coding hard in a language that doesn't erase generic parameters I come back and I am not in my comfortable Java groove and it hurts. | |||||||||||||||||||||||||||||
▲ | Rohansi 2 days ago | parent | next [-] | ||||||||||||||||||||||||||||
This hasn't been an issue for a long time because nobody uses the non-generic collections anymore. That doesn't help you with your reliance on type erasure though. If you're up for it you should give it another try. Your example of subclassing GenericType<X> and GenericType<ConcreteClass> may be supported with covariance and contravariance in generics [1]. It's probably not very well known among C# developers (vs. basic generics) but it can make some use cases a lot easier. [1] https://learn.microsoft.com/en-us/dotnet/standard/generics/c... | |||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||
▲ | pohuing a day ago | parent | prev | next [-] | ||||||||||||||||||||||||||||
> This created an ugly split in the ecosystem because if you were using Container<X> you could not pass it to an old API that expected a Container. Correct me if I'm wrong but allowing this would mean the called api might insert objects wholly unrelated to X. This would break every assumption you make about the container's contents. Why would this ever be allowed or wanted? | |||||||||||||||||||||||||||||
▲ | mrsmrtss 2 days ago | parent | prev [-] | ||||||||||||||||||||||||||||
And yet, Java is trying desperately to fix its generics now with project Valhalla (although value types are their main goal), but it's almost impossible to do without major breaking changes. Without reified generics there's major performance cost when primitive (or value) types are used as generic parameters, because of boxing. Also, .NET has had generics since 2005 when .NET Framework 2.0 was released. |