| So C# definitely benefited with the second mover advantage. It learned a bunch of lessons from Java such as: - No checked exceptions - Properties (I wish Java would add this to the core language instead of relying on things like Lombok as it shouldn't change the IR and really is just syntactic sugar) - Partial classes. This really isn't in contrast to Java because Java has nothing like it. But it is a neat feature for partial code generation; - LINQ. Java eventually added streams but last I checked it still had performance issues and IMHO LINQ is just cleaner; - Conditional compilation. This is really a huge oversight. One of the huge benefits of the preprocessor in C/C++ was conditional compilation. It's great than C# included it. It's bizarre to me that Java hasn't. - Async/await. Honestly I still find C#'s version of this more awkward than Hack's. Experience has taught me that whenever you spawn a thread, you've probably made a mistake as subtle mutlithreading bugs are the devil and cooperative multitasking like you have in Go, C# and Hack is usually far safer and sufficient most of the time. Still, C# is still better than Java here. - C#'s reified generics vs Java's type erasure. I think it was the right decision to break backwards compatibility here (and I don't usually say this). This was pretty early too (IIRC generics were added in C# 2.0). But all that being said, I still think Java has a large mindshare and install base than C# by a mile. it's not sexy so it gets less attention on HN but Java is still massive. As for Kotlin? Much like Scala I see this as nothing more than a curiosity. Android developers seem to like it but I think it's a tiny fraction of Java still. |
The C preprocessor can make it way to easy to break code, for example when it is used for feature flags and/or multi-platform support. If you have N feature flags, you have to compile 2^N different programs. Multiply by M for supporting M platforms.
It also makes it impossible to check whether source code can be compiled. The text inside a
block doesn’t have to be valid source code, but the compiler cannot know whether it has to be. I think that’s why Java ditched it, and I think that makes sense. Adding a more limited feature, like C# did, makes sense, too, though. I’m not sure C#’s variant is limited enough, though. it still is subject to that 2^N problem, but gets saved from its main problems because C# isn’t running on as diverse environments as where lots of C code evolved.