Hacker News new | past | comments | ask | show | jobs | submit login

> The problem with Java since Java 8

I agree with the sentiment, but I'd move up to a version with type inference at least. I have nothing against static types and in fact in a vacuum I prefer them, but the particular brand of OO and "weak" generics that Java and C# have feels like filling forms in triplicate. "var" alleviates that significantly.




Any competent Java IDE automatically generates you a variable declaration from the expression you want to assign to it. It’s actually less keystrokes than having to type “var”. Unless you only use a simple editor that doesn’t perform static analysis, less typing is not a good excuse for using “var”.

Conversely, in Java you often use the diamond operator like in:

    List<String> items = new ArrayList<>();
(Half of which, again, is code completion in your IDE.)

That doesn’t work with “var”. You’d have to write:

    var items = new ArrayList<String>();
while losing the ability to constrain your variable to a narrower type.

The loss of directly seeing the type information in statements of the form

    var foo = bar(x, y);
should meet a very high bar, IMO.


I've found var preferable when reading code.

I've wrought my hands over this and eventually came to the conclusion that developers in every language that started with local type inference have embraced it. So I've mostly ignored my concerns and gone with "var for everything".

If you have trouble with a type then rename the function or variable (AKA your "foo" and "bar" example. The names are bad, fix them. Context matters, we have none here. No one has an editor that displays a single line of code at a time.). But in general we haven't had issues on our projects.

Beyond that, my IDE (Intellij) makes it easy to uncover the inferred type if I really need to be 100.00% sure what it is. In general I don't, because in general I don't care, and even before 'var' I was generally ignoring the type anyways.


I think there is a tasteful way to selectively use var where it makes sense.

Even in your example, narrowing the variable doesn't make much sense - you are in a local scope, you control everything. Narrowing is more meaningful in fields, where var won't work by design.

Locally a well-named variable is often significantly more important than some long, somewhat useless type signature, especially when the right hand side makes it clear.


Generics in Java and C# are _vastly_ different.

.NET has true generics with full type information and struct type parameter monomorphization which works the same way generics do in Rust.

Edit: C# does have type inference for generics, just not the full HM one. It is also quite more capable for lambdas which is a bit frustrating because it does not resolve nested generics otherwise. I miss it - F# does it the way it always should have been.

There are many other differences small and big that arise from the way Java does generics and the fact that primitives can't participate - you will never see `IntStream` kind of workarounds in C#. Some libraries abuse and misuse generics for no profit (looking at you Azure SDK), but it's not as widespread. Shallow generic types are always inferred from arguments.


> you will never see `IntStream` kind of workarounds in C#.

You may not see that in Java in the future either. Java will have value objects from the Valhalla project, and part of the plan is to replace Integer with a value object. Then there will be less of a reason to use raw int primitives, because the JVM can treat value objects much more efficiently than normal objects.


The difference is that C# has been designed with proper generics since version 2 (pushed by F# research group with Don Syme) and is now on version 13. At the same time, structs have been present since version 1.

All APIs and collection types build on this foundation, with standard library leveraging generic monomorhpization for zero-cost abstractions. Code that would have needed C++ implementation in the past is naturally expressed in pure C#. Generics are fully integrated into the type system at IL level, avoiding special-cased types or bespoke compiler handling (besides monomorphization).

This enables numerous zero-cost features: tuples (unnamed/named), structs with controlled mutability and record structs, pattern matching, stack buffers that do not rely on escape analysis, structs with byref pointers for slice types (Span<T> and friends) which a good two thirds of the standard library accepts. Numeric and vector primitives are used in a simple way without setup requirements like Panama Vectors.

While project Valhalla will get Java's foot in the door in some domains, it will remain a less optimal choice than C#, C++, Rust, etc. Java's evolution primarily serves its ecosystem's needs, whereas C# benefits from being a newer language that learned from both Java and C++ and got influenced by F# and other research projects inside MS. This makes C# more idiomatic and terse. The historical drawbacks - platform lock-in, being closed-source, and having relatively weak compiler - have been resolved over the past ~9 years.


yes, this is true. I was talking more about the UX of how to use them, which in both cases is quite painful without type inference.




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: