> Any code which you do not know how to structure within Java's type system can be written with some Objects/Maps/Collections and a bit of runtime logic
Yeah, but that means jumping through hoops because of the lack of the typesystem. And that's what many people don't like, hence the whole thread. For you that might be fine, but please understand that there are other people out that who are not okay with it so easily.
Not jumping through hoops... the point is that you can write untyped code in Java similar to JS with similar complexity. If you really think JS is somehow better in this regard then writing horrible poorly-typed Java is not very different.
> Rather the opposite.
The opposite as in Java is arguably the most relied-upon language for enterprise-grade backend code, because it lacks 99% of features people would want? Okay.
> Every big project that uses reflection/introspection or annotations or some kind of code generation tooling shows that the typesystem is not sufficient.
Annotations and reflection are a feature of Java, they are not external to the language. Annotation and code generation are separate features from the type system - Rust's code generation and annotations are very commonly used. Reflection is equivalent to runtime typechecking that is common in JS. How can you say Java is worse then JS in this regard when the poor parts you point out are basically what JS does?
> And then Java does not even have proper sumtypes or union types (enums only work when the structure is identical and I mean... we could count some strange workarounds with static classes and private constructors that pretty much no one uses due to horrible ergonomics). And these literally appear everywhere.
First of all JS and Python do not have these either, so saying that Java is somehow worse in this regard is ridiculous. Furthermore the usefulness of sum types is fairly limited - what problem are you trying to solve with sum types in Java? Implementing an Either<A,B> is trivial in Java.
I think that applies to you a lot more. You're criticising Java for giving you a whole bunch of features which don't exist in Python or JS, while also saying the language sucks compared to Python/JS because it doesn't have features of Haskell. The fact that you think JS is somehow closer to Rust than Java makes me think you have very limited experience with these languages.
> Not jumping through hoops... the point is that you can write untyped code in Java
Sure, but that already means you are jumping through hoops.
> > > Java's type system is sufficiently powerful for 99% of real-world use cases
> > Every big project that uses reflection/introspection or annotations or some kind of code generation tooling shows that the typesystem is not sufficient.
> Annotations and reflection are a feature of Java, they are not external to the language. Annotation and code generation are separate features from the type system - Rust's code generation and annotations are very commonly used. Reflection is equivalent to runtime typechecking that is common in JS. How can you say Java is worse then JS in this regard when the poor parts you point out are basically what JS does?
Well, maybe I misunderstood you. And with "sufficiently powerful" you just meant "someone can kinda use it to build something". Well then, yes. Saying it just doesn't make much sense to me in a discussion about ergonomics where people complain about type system limitations.
> Implementing an Either<A,B> is trivial in Java.
Okay, let me copy&paste how this can be defined in F#:
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
or maybe a language closer to Java, here it is in Scala3:
enum Either[A, B] {
case Left[A](a: A) extends Either[A, Nothing]
case Right[B](b: B) extends Either[Nothing, B]
}
I'm curious to see the "trivial" implementation in Java that equals the ones from F# and Scala. Mind that both solutions I gave allow to add a "fold(left -> handleLeft(...), right -> handleRight(...))" function which allows to manipulate the content, depending on what it is _without using any casts or reflection_. This is possible in Java, but I don't know any "trivial" solution.
> Sure, but that already means you are jumping through hoops.
Map<String,Object>, Object, a few other things you may need are standard Java, so not sure how this is 'jumping through hoops'. It's not necessarily more complicated, just not idiomatic java - the point is you CAN write shitty JS-style code if you want, how is that an argument for why JS is somehow better than Java?
> Well, maybe I misunderstood you. And with "sufficiently powerful" you just meant "someone can kinda use it to build something". Well then, yes.
Are you not aware that many prominent tech companies have a significant Java stack? Google, Amazon, Uber, Airbnb, Netflix, etc? Are you not aware of major open source Java projects such as kafka, elasticsearch, hadoop, android sdk, etc? What point are you even trying to make?
> Saying it just doesn't make much sense to me in a discussion about ergonomics where people complain about type system limitations.
What doesn't make sense is saying that Java's type system makes it a worse language than JS or Python, or that JS or Python are closer to Rust/Haskell.
> I'm curious to see the "trivial" implementation in Java that equals the ones from F# and Scala. Mind that both solutions I gave allow to add a "fold(left -> handleLeft(...), right -> handleRight(...))"
Here you go:
class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
}
Yes, it's longer and slightly more complicated, mainly because Java doesn't have pattern matching, and yes you can add typesafe fold and map functions to it without reflection. That being said, you gave me examples in languages with more sophisticated type systems than Java - these say absolutely nothing about why Java is worse than Python or JS.
> Map<String,Object>, Object, a few other things you may need are standard Java, so not sure how this is 'jumping through hoops'
When you put various things into this map and then later get them out and want to work with them, you will have to cast them to be able to do anything useful with them.
> the point is you CAN write shitty JS-style code if you want, how is that an argument for why JS is somehow better than Java
For the sake of our discussion: I have never said that JS were somehow better than Java. I much prefer statical type systems and would always pick Java over JS for a personal non-browser projects. But that's not the point of this discussion, so I'm playing "devil's advocate" here. It's important to understand and accept the shortcomings of statical type-systems - that's what I try to explain here.
> What doesn't make sense is saying that Java's type system makes it a worse language than JS or Python
You need to re-read what I (and the others in this subtread) have written. It is completely valid to criticize one part of language X compared to language Y without implying that this language X is worse than another language Y overall.
> [Java Either implementation]
> Yes, it's longer and slightly more complicated
And not only that, it is also not equivalent to the F# / Java examples. Or if it tries to be equivalent, it is buggy.
E.g.:
Either.left(null)
Now I have an Either that is neither left nor right. Compared to the Scala example (because Scala also has to deal with the existence of null):
Left(null)
This will create an instance of the type Left which contains a null-value. As I said, if I add a `.fold` method, then it will fold over the null. E.g.:
Left(null).fold(left => "Left value is " + left, right => "Right value is" + right)
This would return the String "Left value is null". You can't do this with your example implementation in Java, because the information is lost.
It is _not_ trivial to do that in Java, even when relying on already similar functionality like the built-in Optional type.
> When you put various things into this map and then later get them out and want to work with them, you will have to cast them to be able to do anything useful with them.
Considering this is entire hypothetical is a edge case, that's a minor inconvenience.
> But that's not the point of this discussion, so I'm playing "devil's advocate" here. It's important to understand and accept the shortcomings of statical type-systems - that's what I try to explain here.
That is the point of the discussion, the original claim I was objecting to was:
'This is a massive expressive hole which (along with lacking type inference) I believe is responsible for a lot of the hate towards statically typed languages.'
You're pointing out weaknesses in a subset of statically typed languages, and these are only weaknesses when compared to better type systems - not when compared to dynamically typed languages. I never claimed that Java had a perfect type system - I prefer Haskell and Rust.
> You need to re-read what I (and the others in this subtread) have written. It is completely valid to criticize one part of language X compared to language Y without implying that this language X is worse than another language Y overall.
It's not valid when you're using Rust or Haskell to show weaknesses in Java relative to JS. The original context was Java/C#/C++ vs Python/JS.
> Now I have an Either that is neither left nor right.
You're right. Here's a simple example without this problem:
class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(value, null, true);
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(null, value, false);
}
private final L left;
private final R right;
private final boolean isLeft;
private Either(L l, R r, boolean isLeft) {
left = l;
right = r;
isLeft = isLeft;
}
}
> It is _not_ trivial to do that in Java, even when relying on already similar functionality like the built-in Optional type.
It is trivial, it's just more awkward and lengthy but not complex at all - also no Optional. Plus there are stable libraries providing types like Either<A,B>, and other functional language features. Anyway, I'm not here to defend Java type system against Haskell, my point is that Java type system is a huge feature when compared to JS or Python.
> Considering this is entire hypothetical is a edge case, that's a minor inconvenience.
I believe this is not an edgecase. I have to deal with that almost everyday and I'm working with a language that has a much more advanced typesystem than Java. But I guess there is no hard data for that, so everyone can believe what they what. :)
> You're right. Here's a simple example without this problem:
If it's so trivial, then why do you even have to fix something in your first approach. Also, you second approach still has flaws and is not equivalent. Maybe you want to figure it out yourself this time? :)
Anyways, I guess we are talking different points. Have a nice day!
Not jumping through hoops... the point is that you can write untyped code in Java similar to JS with similar complexity. If you really think JS is somehow better in this regard then writing horrible poorly-typed Java is not very different.
> Rather the opposite.
The opposite as in Java is arguably the most relied-upon language for enterprise-grade backend code, because it lacks 99% of features people would want? Okay.
> Every big project that uses reflection/introspection or annotations or some kind of code generation tooling shows that the typesystem is not sufficient.
Annotations and reflection are a feature of Java, they are not external to the language. Annotation and code generation are separate features from the type system - Rust's code generation and annotations are very commonly used. Reflection is equivalent to runtime typechecking that is common in JS. How can you say Java is worse then JS in this regard when the poor parts you point out are basically what JS does?
> And then Java does not even have proper sumtypes or union types (enums only work when the structure is identical and I mean... we could count some strange workarounds with static classes and private constructors that pretty much no one uses due to horrible ergonomics). And these literally appear everywhere.
First of all JS and Python do not have these either, so saying that Java is somehow worse in this regard is ridiculous. Furthermore the usefulness of sum types is fairly limited - what problem are you trying to solve with sum types in Java? Implementing an Either<A,B> is trivial in Java.
> I diagnose that you are suffering from the famous http://wiki.c2.com/?BlubParadox
I think that applies to you a lot more. You're criticising Java for giving you a whole bunch of features which don't exist in Python or JS, while also saying the language sucks compared to Python/JS because it doesn't have features of Haskell. The fact that you think JS is somehow closer to Rust than Java makes me think you have very limited experience with these languages.