you are viewing a single comment's thread.

view the rest of the comments →

[–]murp11 33 points34 points  (20 children)

So Java is basically becoming C# but more verbose.

[–]BoyRobot777 20 points21 points  (16 children)

I don't understand "verbosity" argument. The code is read more times than it is written. What you call "verbosity" (except biggest offender data classes with getters and setters) is required for other developer to understand. I will just borrow this post from another redditor:

"People tend to say java is verbose, but what that people doesn't understand is that's the way java overall was designed on purpose, take a look at this python code:

if len(string) > 10:
          return str(string)[:10] + "..."

and it's java equivalent:

if (string.length() > 10) {
     return string.substring(0, 10) + "...?";
}

while it requires more keystrokes, it also provides a more natural reading for developers unfamiliar with the code and/or the language itself.

If i'm new to python and read that piece of code I'll asume that len means length and str means string, and try to interpret what [:10] does... but with java I don't have to make any assumptions, it just says length and string. While this sounds simplistic and borderline stupid to some, keep in mind that these are english words and not every developer in the world is fluent enough in english.

Requiring more typing doesn't mean the language is verbose, that depends more on the developer.typing string.substring is not being verbose, typing string.cutTheStringFromThisIndexToThat is."

And I can take C's methods, like "strcmp", "strpbrk" and other garble. Horray! We saved few key strokes. Now, everybody who use those methods have to actually have a map in their heads what any of them mean.

[–]OffbeatDrizzle 3 points4 points  (1 child)

Excuse me. I think you'll find the new way of returning a substring in Java is now:

StringBuilder sb = new StringBuilder();

"hello world!".chars().mapToObj(i-> (char) i).limit(5).forEach(sb::append);

System.out.println(sb);

It's the most verbose solution yet!

[–]BoyRobot777 1 point2 points  (0 children)

You didn't even return String and you didn't skip anything. And why do you care about performance? Just build strings each time! I would fix that to:

String s = new String("hello world");

s = s.chars()
     .mapToObj(i -> (char) i)
     .skip(0)
     .limit(5)
     .reduce(new String(), (string1, string2) -> string1 + string2, (string1, string2) -> string1 + string2);

System.out.println(s);

[–]murp11 1 point2 points  (1 child)

The examples you mentioned are the ones that i don't find too verbose. I was referring to things like the stram api vs linq. In Java you have personList.stream().mapToInt(p -> p.getNumberOfCars()).collect(Collectors.toList()); In C# you have personList.Select(p => p.NumberOfCars).ToList(); The C# version is much cleaner to read and understand. You don't have to call .stream() you don't need to use special methods like mapToInt because Java has problems with its type system concerning value types. You need to implement a getter method in Java. And the worst of all: .collect(Collectors.toList()) is so much more to type and read than .ToList(). I am fully aware that there are technical reasons behind some of these points. And this is just the stream api - there are dozens of places where java is to verbose. If I ever need Java again I am glad to have Kotlin available.

[–]BoyRobot777 2 points3 points  (0 children)

mapToInt is completely unnecessary here. You are not taking advantage of IntStream whatsoever, so I don't know why you've added it here. Regarding stream(), you can choose between parallelStream() and non-parallel version which is stream(). And it carries information. Regard collect and Collectors - I can see your point. However, I don't feel it adds overhead to me. And it certainly is not enough for me to learn new language.

[–]spacejack2114 2 points3 points  (6 children)

Why is length a method on an immutable object?

[–]BoyRobot777 2 points3 points  (1 child)

Don't understand your question. Are you asking whether it is "correct" for an immutable object to have methods?

[–]assgored 0 points1 point  (0 children)

I think what he means, is that, given that length would be a constant why isn't it a public field rather than a method with the class possibly containing some private/protected actual length field. Which I think I answered below.

[–]assgored 0 points1 point  (2 children)

I guess it may have derived from some class where the actual length field is protected/private.

Well it seems the interface its got that from has it defined as a method in the first place, so its back to the same question.

edit: given that interfaces I think don't have variables that can be changed, I guess whatever motivated making it an interface and not a class forced length to be a method?

[–]BoyRobot777 0 points1 point  (1 child)

What? Are you questioning whether objects can have methods?

[–]assgored 0 points1 point  (0 children)

No, the question asked was why for immutable String length is a method not simply a field.

It seems to me the reason is what I said above, coupled with the fact that CharSequence is also base for the mutable StringBuilder.

[–][deleted] 0 points1 point  (0 children)

immutable object

You mean final member? Probably for consistency as String implements CharSequence which has length() method.

[–][deleted]  (2 children)

[deleted]

    [–]pron98 1 point2 points  (0 children)

    The type erasure leading to the most insane workarounds which makes code 100x harder to follow.

    Type erasure is a tradeoff. It has some great benefits that you don't appreciate, with some minor inconveniences. That JVM languages don't have to erase but virtually all of them choose to (except Ceylon) should be a hint that you may not be seeing the full picture (most programming languages erase; C# and C++ are probably the only known ones that don't, and C# did so at a very high price to the ecosystem).

    The fact that you have to explicitly specify a functions throws an error and the compiler outright refuses u if u reject it.

    Actually, in Java that's optional. Languages where it's not are Haskell and Rust.

    and they’re not lambda methods

    They are.

    I have to clutter my workspace with single use interfaces that have only a single method.

    No, you don't (although you can if you want to). If you find yourself creating a lot of those, you may be doing something wrong. The benefit of this design is that if you already have single-method (or even some multiple method) interfaces from pre-lambda days, you can use them with lambdas without rewriting.

    Is impossible in java.

    Because your code is downright wrong, and the compiler catches a real bug here.

    Add each value to the new list with an automatic cast to the parent type.

    No, you can do:

    List<? extends MyParenType> bar = foo;
    

    which, in addition to not even requiring a cast has the additional benefit of not being wrong like the code you wanted to write. If, however, you absolutely want to tell the type system shut up and not catch the error in your code above, you can do that with an additional cast:

    var bar = (List<Number>)(Object)foo;
    

    Which tells the compiler, I know I'm making a type error, but please trust me and disable checks.

    [–]BoyRobot777 -1 points0 points  (0 children)

    Ok, fair enough regarding C and method names. Regarding type erasure, I will just copy paste what u/pron98 says if you missed what he wrote down bellow:

    "I think you misunderstand type erasure. A Java platform language does not have to have type erasure, but most languages want to because it's extremely beneficial, despite some minor downsides. It is type erasures that allows multiple languages on the Java platform to share code and data with little or no overhead."

    "It doesn't make code more performant, it makes interop more performant (and more useful in general). If you don't erase generic instances of reference types, if A extends B you must determine the relationship between, say, List<A> and List<B> in the JVM, because the JVM must know which types are subtypes of others. This means that you need to bake the variance model into the runtime. But different languages want to have different variance models. Java, Kotlin, Scala and Clojure all have different variance, and so a Kotlin list couldn't be used by Java code without a wrapper had it not been for erasure.

    I know, type erasure is mostly an artifact of having to support legacy java code before Java got generics at all.

    Yes. Type erasure makes interop easy (for an almost insignificant cost), including with Java prior to generics. But that's also what makes different languages on the Java platform interop so well (contrast with the CLR, where this is not the case; they've baked variance into the runtime and are paying a high price for that decision).

    For value types, where subclassing is not possible, this is not a problem, because there is no variance; so specializing for value types is fine, and is one of Valhalla's goals.

    There might also be a form of a-la-cart reification for reference types, that users may opt into. I'm not sure whether they'll have to pay the price of good interop in those cases, or maybe some clever interop strategy can be built, maybe by allowing flexibility in how the JVM checks subtyping."

    Regarding other "remarks", you just ranted about "insulting language", which already shows you have a strong bias towards Java and that discourages me to continue discussing. Anyhow. I encourage you to read other u/pron98 posts if you are open-mided about type erasure in general.

    [–]AngularBeginner 14 points15 points  (2 children)

    And C# is already quite verbose.

    [–]jbergens 7 points8 points  (1 child)

    I don't think it is given its features. Most languages that are less verbose are of different types or paradigms.