Hacker News new | ask | show | jobs
by rubber_duck 2114 days ago
Not really - Java designers were just plain wrong and it took forever to admit it - things like local type inference (var) made the language pointlessly verbose for ages, and simple features like lambdas made the standard libraries terrible.

There was a 8 year gap where C# users could use stuff like enumerable operators while Java users were stuck in the stone age of writing loops for collection manipulation in a high level language ...

4 comments

It's a feature, not a bug.

Java is stable, and evolves with a huge amount of thought (they employ theorists to model the impact of changes to the Java language even.)

The benefit of this is a long-term platform, and an excellent implementation. Due to this Java has become the platform where the majority VM research is done, which means Java has many excellent state-of-the-art garbage collectors and a JIT a level beyond that of C#.

Java has a long history of saying “we don’t support that feature because it’s d-a-a-a-angerous.” Personally, I think that’s an insult to Java programmers, but Java programmers don’t seem to take it the same way. They’re happy that somebody at Sun or Oracle is able to keep all the sharp corners away from them.
You know, coming from Java and seeing new languages like Go say the same thing except for features that Java had essentially forever is just maddening.
So...if somebody hands you responsibility for a codebase, you're happier when the language has sharp corners and bleeding edge scars?
I’m annoyed that things aren’t “complex,” “brittle,” “difficult,” etc.; they’re just “dangerous.” They’ll draw blood through the computer screen. I know programmers who have actual fear of pointer arithmetic even though they have no idea what it is.

To be fair, Java has a lot to recommend it. For one, there are, of course, an incredible number of packages available to build off of. But I find it incredible that the language that replaced finalizers with phantom references still says pointers are too dangerous for programmers.

>which means Java has many excellent state-of-the-art garbage collectors and a JIT a level beyond that of C#.

Unfortunately this isn't enough to make up for the latency hit from not being able to directly stack allocate things like C# allows (especially with its recent addition of Span<T>).

> make up for the latency hit from not being able to directly stack allocate things

Java does better than direct stack allocation - it does automatic scalar replacement instead.

Can automatic scalar replacement turn my ArrayList<Pair<Long, Double>> into the equivalent of std::array<std::pair<int64_t, double>, N> (or Span<Tuple<long, double>>)?
It doesn't turn it into the equivalent of another data structure, and it doesn't allocate it on the stack, that's why it's better. It turns each value in the collection into a dataflow edge which then goes into a register, or the stack, or anywhere.
This seems really interesting, do you have any sources I can look into for more information along these lines?
so does any decent compiler. But to do that in java you first have to prove it is safe, which is hard.
Java has state of the art garbage collectors because java programs are state of the art garbage generators.

JVM is not the best in all areas.

Java designers don't follow fashion, they rather wait to see what actually works when the dust settles and how to keep those binary only 25 year old jars running on modern JVMs.

I have been working with Java, .NET and C++ since they exist, and C# being more feature rich than Java doesn't help if the libraries or OS support that a customer needs isn't there.

C# doesn't follow fashion either, it does things that actually work before the dust settles on them.

I think you'll find many people outside the HN crowd also appreciate their approach over trying to appease the kinds of customer needs that involve keeping 25 year old binary only jars running.

To me .NET Core is a shining example of that

> over trying to appease the kinds of customer needs that involve keeping 25 year old binary only jars running

C# doesn’t break too many things while it evolves. Example: https://docs.microsoft.com/en-us/dotnet/api/system.collectio... That class was introduced in .NET 1.1 way before generic, still present in the most recent .NET Core 3.1.

They sometimes deprecate higher-level stuff, but very conservatively so. E.g. asp.net web forms (2002) is deprecated, while windows forms (also 2002) is still supported.

Try to run random .NET Framework Assemblies on .NET Core or .NET Native, this is what Java philosophy tries to avoid.

Forms designer is still broken on .NET 5, and it might not make it to the final release.

This is a single breaking jump after 20 years. This migration is really needed and well considered.
.NET Core has been so good managed, that I a project back in the .NET Core 2.0 days to port an application to Java, because the customer wanted to move the application to UNIX (not just Linux flavours), and not all necessary features could be done in Core.

To this day there are plenty of libraries that are yet to run on either Core or outside UNIX.

Plus not everyone is happy how the whole Core, .NET 5, .NET Native, Reunion, UWP, CoreRT, Xamarin, MAUI, Blazor is being managed.

A language alone isn't enough.

I mean .NET Core is targeting Linux, is that really a sign of mismanagement?

And to your second point.. I mean you're comparing concepts at very different levels of a stack. Your list includes a language runtime, a web framework, an OS specific application format/framework?

It's like saying "Java, HotspotVM, JavaFX, Tomcat, Android APK, Vert.X"...

In reality it's ".NET Core and .NET Framework".

And while there have been some growing pains as the term .NET became overloaded, it's always been clear .NET Core is where they want people to be, .NET Framework exists because migration to a new platform wasn't going to happen overnight.

Every year there's more and more .NET Core compatibility, they've done a good job with .NET Core so more people are willing to use it (and port packages to it)

https://docs.microsoft.com/en-us/dotnet/standard/choosing-co...

Naturally I am comparing all levels of the stack, as I mention on my comment a language alone is useless.

Yes, the future is .NET Core, however pretending that outside Windows it can match Java offerings just reveals a complete lack of knowledge of all kinds of platforms that have Java support available for them.

Guys like PTC, Aicas, Gemalto, microEJ doing embedded real time Java, selling M2M devices, IBM and Unisys mainframes, 80% of the mobile world (even if it is an adulterated flavour of coffee), smartcards, blue ray players, healthcare and TV settop boxes, kiosks and plenty of other use cases.

.NET is catching up with 25 years of Java doing cross platform development, while anything that came out of Redmond has been mostly Windows only for 20 years.

.NET Core only supports the three major mainstream OSes, zero support for anything else, and has the growing pains of a platform where plenty of third parties are yet to release anything on Core.

Sitecore just released their first version on .NET Core earlier this month, and I don't see anyone rushing to upgrade.

Doing WPF, Forms? Good luck with many GUI component libraries.

Apparently the designers are going to miss .NET 5 for full stability.

The beautiful thing with being a polyglot consultant is that I don't have to convince myself that I am using the best stuff as "Developer X", I just use whatever stack the customer asks for and then move on.

> Yes, the future is .NET Core, however pretending that outside Windows it can match Java offerings just reveals a complete lack of knowledge of all kinds of platforms that have Java support available for them.

I have no idea what on earth you're on about... you didn't bring up anything I didn't know as far as places where various JVMs live.

This just reads like another distraction from the topic of language direction just like your last comment trying to confuse web frameworks and language runtimes...

Why is .NET Core supposed to be blindly chase platform parity with JVM down, especially down to embedded devices?

You realize the JVMs used on embedded devices aren't the same ones used on desktop right?

Like there are C# frameworks for embedded development on microcontrollers, why on earth would that be .NET Core's domain? Do you think HotspotVM is running on those smartcard microcontrollers?

-

Your entire comment you seem to be under the impression .NET Core exists to be a drop-in replacement for the JVM for every usage.

Which is especially strange because you're using JVM as a generic term for every JVM in parts of your comment, which would maybe be comparable to the CLR at best (but still be an odd comparison to make)

If anything you're speaking to the strength of C# and a product like .NET Core, they're not chasing the same goals that skewered the development pace of Java.

The C# team is not worried that their language standard changes might be hard on people embedded runtimes in smart cards or 25 year old binary only jars

The same mentality is why C# paid the price to break backwards compatibility on generics back in the 2.0 days, and enjoyed a much more powerful implementation going forward in perpetuity.

You're free to feel one approach is better than the other, but it's non-sequitur at best (and disingenuous at worst) to start spouting off about how the JVM runs on smartcards and so that means .NET Core is supposed to be matching that in a conversation about language growth...

> .NET Core only supports the three major mainstream OSes, zero support for anything else

This is true, but this level is support for the majority of use cases. I do personally find it very annoying that refuse to support 32-bit Linux tho.

> has the growing pains of a platform where plenty of third parties are yet to release anything on Core

This was true a few years ago, but certainly isn't now. I honestly can't even remember when I last tried to use a library that didn't have dotnet Core support.

C# has been moving much more quickly since then, async/await comes to mind as a feature that didn't work out
How did they not work out??
Mainly because its the colored function problem. You end up having to change the call stack all the way up to Task<T>. Once you start using them, everything is a Task.
Or polluting the code with a couple of Task.Run() to avoid having to do just that.
I've never had anything but problems trying to run Java apps. Maybe in server land it's been great but in desktop land, outside of Minecraft, it's always been hell for me.
> "Java designers don't follow fashion, they rather wait to see what actually works when the dust settles and how to keep those binary only 25 year old jars running on modern JVMs."

Yup, for better or for worse, Java will be the COBOL of the 21st century.

Apparently 21st century developers don't have much issues dealing with UNIX and C, just about 10 years younger than COBOL, speaking of which, both about 30 years older than Java.
One can be staid and stale at any age.

Aside from that, the average 21st century developer would have a meltdown trying to use C.

> local type inference (var) made the language pointlessly verbose for ages

I guess that this is a question of taste.

What for you is "less verbose" for me is more confusing to read. I like to see the types as they complement variable naming. To avoid typing a few letters the code will for ever require me to double check the types with help of the IDE.

I have worked in medium sized corporate companies. The code base is quite big and one of the 20+ development teams may get transferred a project from another team (does not happens super-often, but it happens) or they may create pull-requests for bug fixes (this is more common).

Clear and easy to understand code is life saving. In one of the companies I worked for a Javascript team send a -1 instead of a "-1" the cost ramped up the hundreds of thousands of dollars and our clients were not happy about it. Rollback mechanisms were used as fast as our clients detected revenue problems on their own customers.

And the tests did not got the error as the values is used at the integration layer between our clients and us.

I see safety an increasing value as our programs control more and more money and more and more services. And, I have to admit, I feel more comfortable with more verbose code.

You just need to use var properly. I.E. only when you can tell the type from the rvalue.

var a = new ArrayList<T>();

not:

var a = o.getThings();

> You just need to use var properly.

That is a very good point. I find the diamond operator more of my taste as it requires you to think if you want to expose ArrayList or List.

List<String> list = new ArrayList();

But, as you point, the second example removes information that will require to spend time to check types each time that someone reads the code. I do not like that.

I use auto-complete and I type quite fast, so, I do not see to write code as a problem. I spend most of my time understanding the functional needs, looking for better patterns or algorithms to implement performance-critical sections or finding names for exposed APIs that state clearly its function when I "write code". But, most of the time, I am just reading my old or other people's code to just change a few lines or decide on a local refactoring.

^This

Here, the first is much less verbose, but still clear:

    var x = new Dictionary<string, MyComplexType>();
    Dictionary<string, MyComplexType> x = new Dictionary<string, MyComplexType>();
But here, it’s ambiguous what the type of `x` is without Intellisense:

    var x = y.GetStuff();
Did you spend any significant time working with C#?
> Did you spend any significant time working with C#?

I have no experience with it at the corporate level. There, I have seen, it mixes a lot with .NET. So, I guess that the corporate equivalent to Java is "C#/.NET".

I spend some time several years ago with C# in Unity3D, thou.

I really liked the C# language. I found the Auto-Implemented Properties a neat compromise between encapsulation and verbosity (Verbosity has no value if does not add information).

Java is trying to be everything to everyone and that is a mistake. I liked Java more in the past, and I would have added just a few things from the past iterations of the language (e.g. Modules is a good idea that actually simplifies the language and moves much code to "frameworks" instead of being part of the core language).

C# seemed more focused on its initial style were Java is stretching all over the place.

You haven't used much LINQ, pattern matching, spans, ranges, default interface methods, non null references in C#, I guess.
Pointless typing and verbose code has nothing to do with writing code - it's all about code being readable.

Java type declarations can be 20+ characers - just scanning through the code and having to skip all that junk makes my eyes more tired reading through. Types are implicitly deducible when you know the codebase 90% of the time (and should be added when they are not), and if you don't know the context you will be slow no matter what.

> when you know the codebase

Yes. When I was younger I worked in solo projects. I knew my code almost line by line.

In my last decade, in middle sized companies, nobody knows all the hundreds of micro-services code. And code changes while on vacation, that can be 6 weeks of the team working without you. That is not ideal, but in such a big code base it is difficult to have everyone reviewing all the changes on a single micro-service, impossible to have all 20+ teams reviewing all of each others code.

Different problems need different solutions and code styles, I guess.

My point is that in a good code base types should be obvious from context. If you don't know the context then you will be slow (and make a lot of mistakes) no matter what the type say because you'll likely misunderstand the domain logic (context) unless it's something trivial. I would hate to work somewhere where I'm expected to randomly drop into micro services I didn't have anything to do with and debug/support them - sounds stressful.
Even then they fumbled the execution. Why on earth would they make streams without support for native types?
Yes, but that seems like a clunky add-on. Something as basic as iterating the characters in a string should not require special constructs like this IMO.
How would you have implemented it, while satisfying their constraints of extreme backward-compatibility?