Hacker News new | ask | show | jobs
by moonchild 2093 days ago
I don't particularly like java. Most don't. But it's undeniably well designed.

Some of its design choices have fallen out of favour in recent times—I still disagree with their elision of unsigned integers—but they're generally at least defensible.

2 comments

No, it is not well designed. Just about every major feature has something incidentally or fundamentally wrong. It is proof that a language does not need to be good to succeed. But it does need a miracle.

Java took off because it offered developers a path out of serfdom to Microsoft, at a time before the smartphone era somewhat reduced their market power. Once it had enough users to benefit from network effects, its future was assured. It took Sun putting billions of dollars into promoting and supporting it to get there.

Sun's commitment to Java probably killed the company, in the end.

There were better-designed languages at the time, and there have been plenty of much better-designed languages since, that have or will fail to displace it. Rust might be counted among these.

Rust and Java are so far apart it's not even funny.

Can you give some examples of parts that are not well designed?

Not GP, but there's a type unsoundness bug with the fact that you can assign an array of a subtype to an array of a super type (apologies if my syntax is off; I haven't written Java in a while):

class Animal {} class Cat extends Animal {} class Dog extends Animal {}

Animal[] cats = new Cat[1]; Animal dog = new Dog(); cats[0] = dog;

This will compile fine but throw an error at runtime. The only possible way to avoid runtime errors with assigning a Cat array to an Animal array is if you only put Cats in it, at which point it would make more sense to just use a Cat array, so it would have been better design to make assigning a Cat array to an Animal array a compiler error.

Huh, I'm surprised the problem is present. Presumably this is valid?

  Animal[] a = new Animal[2];
  a[0] = new Dog();
  a[1] = new Cat();
If you can upcast Cat to Animal, why can Cat[] not be converted to Animal[] in the same way?
Depends on whether you intend to write into the array, or only read it.

If you could make sure the array is read-only (which you can't, in Java), it would make sense to say that "Cat[]" is a subclass of "Animal[]".

The problem happens when you write. "Animal[]" means that you can put any kind of animal (not just Cat) into the array; and this is not true about "Cat[]"; therefore, "Cat[]" shouldn't be a subclass of "Animal[]".

Unfortunately, Java treats "Cat[]" as a subclass of "Animal[]", and then runtime errors can happen when you write to the array. And because of backwards compatibility, this problem is not going to go away.

Later they got it right with generics. "List<Cat>" is not a subclass of "List<Animal>". (But both of them are subclasses of "List<? extend Animal>", which means: a read-only list of Animals.)

> If you can upcast Cat to Animal, why can Cat[] not be converted to Animal[] in the same way?

Basically, because it's not type safe (for the reason I gave above). It doesn't really help expressivity to be able to assign a Cat[] to an Animal[], but as you can only use it safely if you only put cats in it, so you might as well just make the variable Cat[] instead of Animal[]. See the section on arrays in this wikipedia article: https://en.wikipedia.org/wiki/Covariance_and_contravariance_...

Generally - but signed bytes (at least as implemented) are really fucking stupid.