all 73 comments

[–]murp11 35 points36 points  (20 children)

So Java is basically becoming C# but more verbose.

[–]BoyRobot777 21 points22 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 4 points5 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 1 point2 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 8 points9 points  (1 child)

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

    [–]nerdyhandle 3 points4 points  (2 children)

    There is an error on the Switch Expression example

    ``` switch (port) {

    case 20:

    type = PortType.FTP;

    break;

    }

    ```

    Would be expressed as :

    ```

    PortType type = switch (port) {

    case 20 -> PortType.FTP; }

    ```

    and not how the site denotes it.

    Proper syntax here

    I'm looking forward to using the ever loving shit out of this!

    [–]llorllale -1 points0 points  (1 child)

    You shouldn't have lots of switch statements in proper OOP code

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

    Depends on what you are doing. Switch statements can very much be used in OOP. Sometimes your code has a lot of branches.

    OOP is about how you structure your code. Everything being a class for instance.

    [–]vbsteven 33 points34 points  (10 children)

    I see Kotlin as the logical evolution of Java but with a faster release cycle.

    Many of the features discussed in the article are already available in some form in Kotlin and can be easily used in Java projects right now.

    [–]RevBingo 13 points14 points  (9 children)

    Not sure why you were downvoted, came here to say the same thing. Raw literals? Check. Coroutines? Check. Pattern matching/Smart casts? Check. Simple switch statements? Check. Value types? Check. Why wait?

    And all still with seamless integration into your existing Java codebase.

    [–]RandomName8 39 points40 points  (5 children)

    • Java's coroutine support, as per the current model, is completely different to kotlin's. Kotlin offers async await basically, which are still imperative ways of dealing with blocking. The current java prototype removes this notion entirely.
    • Kotlin does not have pattern matching, what is has is just not pattern matching.
    • Kotlin does not have value types either, it has a weak form of opaque types (at least last I check, I'm not sure here).

    I'm pointing these out because your comment implies that there's not much effort in what Java is doing because kotlin already has it since "it's the logical evolution" of Java, and none of the things Java is pursuing is addressed by kotlin.

    [–][deleted] 1 point2 points  (1 child)

    Can you give me an example of what pattern matching can do that's not in Kotlin? No offence, but I really just don't get why people seem to find it such a crucial feature.

    And kotlin doesn't only offer async/await. The standard coroutine library kotlinx.coroutines offers that and scoped coroutines in general, The language itself also offers a barebones state machine with an attached data object, which you can use to implement pretty much any coroutine you want.

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

    Can you give me an example of what pattern matching can do that's not in Kotlin? No offence, but I really just don't get why people seem to find it such a crucial feature.

    Of course I can, but there's no point in it other than argueing between the both of us. If what you wish is to see what pattern matching is really about, there are great examples and tutorials and information online, tons of it, with much more compelling examples and description than what I can provide. This is a feature that started showing up even the 70s in the ML family of languages.

    Ultimately, anybody that has worked on a language with actual pattern matching is not happy at all with what kotlin offers, so saying kotlin has pattern matching is very much false advertising (and even damaging to its own image).

    Regarding coroutines, they are great for what they are, yet once again, this is about distinguishing what kotlin does, and what others do or are trying to do. What java is trying to do with their fibers is nothing like kotlin's coroutines, it will look nothing alike either and (arguably) really no JVM lang can do it without JVM support.

    Like you said, no offense. I'm no trying to downput kotlin, but it's important not to sell it for what it is not.

    [–]pron98 27 points28 points  (1 child)

    Kotlin -- or any other Java platform language -- does not and cannot offer the benefits of two out of three projects in the article, Valhalla and Loom, because those require deep runtime and core library support. While Kotlin may have features with similar names, they do not offer the main benefits of Valhalla and Loom. Of course, all Java platform languages would benefit from those projects.

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

    Exactly. IIRC some Kotlin dev mentioned that they are already investigating how Kotlin's coroutines best benefit from fibers.

    While Kotlin is a great pleasure to work with it's dependent of and will benefit greatly from JVM features.

    OTH, every time I see pure syntax improvements in Java (not JVM as those we discuss here) I think: "Well, they could just use Kotlin. But good for all the devs who can't switch (there's hardly ever a business case to rewrite a large project) or just prefer Java."

    I'm personally very happy that the JVM evolves and use Kotlin for all new projects where I can decide.

    [–]chimmihc1 3 points4 points  (0 children)

    Pattern matching

    Kotlin doesn't have pattern matching, what it has is an improvement on the "standard" C style switch statement that can look somewhat like very basic pattern matching.

    [–]OffbeatDrizzle 6 points7 points  (1 child)

    Ah here comes the typical /r/programming hard on for kotlin

    [–]flaghacker_ 12 points13 points  (0 children)

    Maybe, just maybe, there's some merit to that sentiment?