Comment by DarkNova6
13 hours ago
C# actually has a fair amount of gotchas and Java aims to make these explicit. So where C# mostly copied C from a low level perspeCtive, the Java guys approached this high level and analyzed in detail which constraints give you what kind of benefit.
So where in other languages, the struct/class taxonomy is binary, Java allows more granular control, reflection the semantics of the underlying domain. Snd as it turns out, structs have a wide range of footguns, especially in a parallel context.
Could you actually explain/exemplify any of the gotchas and what's been made better (or is this just handwaving)?
I've been let down by structs in C# repeatedly. First of all, there are no constructor guarantees and you can never fully avoid them representing an illegal state. Which, wouldn't be so bad if there was some kind of post-construction validation, but this also isn't part of the language.
This is fine if you hand-roll all your code yourself, but I often use mapping libraries to lower the code footprint and the problems resulting from schema changes are subtle and fly under the radar. This is different from classes with hard construction guarantees, which Java would offer with their "integrity by default" mantra. Where you can opt out of integrity for performance benefits (which is also part of the design).
And Nullability in C# is an absolute nightmare. The type system has completely different rules for nullable types that generalize over classes and structs and there is no generic such as a "Nullable type".
It's just lots of minor annoyances that don't form a cohesive whole.
Part of the reason Java hasn't reified generics is because C# did and it was a real big headache that also limited non-C# languages on the C# runtime (CLI?). Everything had to be recompiled to work with newer C# runtimes. While it's pretty easy to run a bunch of language on the JVM (Javascript, python, ruby, clojure) doing the same for C# is somewhat a nightmare, particularly for non-type aware languages.
For example, Imagine you have an api like `void do(List<Foo> foos)`. In the erasure environment of the JVM that looks like `void do(List foos)`. From python it's pretty easy to call with a `foos = [Foo()]`. But not so much if your python implementation needs to figure out how and if it can coarse it's `List` type into a `List<Foo>` type.
I don’t think that’s the case. You can absolutely implement a type-erased language on top of the CLR. Your language will just have the same constraints of a type-erased language like Java.
Having reified generics in the CLR just lets you store more type information. There isn’t much of a trade off for CLR end-users.
Compare this to the constraints and workarounds that Kotlin and Scala have due to type-erasure on the JVM.
4 replies →
The gotcha is the potential boxing of structs onto the heap, but that can be avoided using `ref struct`s.
https://news.ycombinator.com/item?id=48599273
Why would you presume the parent is "just handwaving"? It's odd how people in the .NET community struggle to earnestly engage in conversation with Java folk. The reverse isn't true.