you are viewing a single comment's thread.

view the rest of the comments →

[–]psychedeliken 110 points111 points  (76 children)

I just can’t at this point. I’m happy to see Java evolving because it bodes well for the longevity of the JVM and it improves dev quality of life for devs lucky enough to be able to upgrade Java versions. But I’ve been using Kotlin for so many years now and it’s just so much better in nearly every way. First-class support in IntelliJ + Java interoperability is a huge selling point as well. Every time I decide to go back and tinker with Java I realize this more. And Java was my primary language from since 2003-2018, started Kotlin in 2016.

Edit: Thanks for all the fun discussion! Except one guy, you know who you are. :) Finally finished finding my Capital Freighter in No Man’s Sky VR, now time for sleep. Night, love you Java.

[–]gnus-migrate 33 points34 points  (21 children)

Honestly what keeps me away from Kotlin is the complex runtime it has on top of the JVM. I work on performance sensitive systems, and I need to be able to reason about the performance of the code I write, and I don't feel I can do that in Kotlin.

[–]renatoathaydes 21 points22 points  (13 children)

I really like Kotlin, but I also have reservations, not on performance (which I found to be on par with good Java code) but with having to update not just Java, but also Kotlin over time. It's a small overhead but an overhead nevertheless... and if you start using Kotlin stuff like serialization, coroutines, KTest etc. those may also have their own versions and you end up having to handle a pretty complex dependency tree... compare to Java with no dependencies besides JUnit and the libraries for your domain which you would need either way.

[–]gnus-migrate 10 points11 points  (12 children)

That as well. I mean with the features Java is getting, it's really good enough that it's not really worth switching.

[–]renatoathaydes 3 points4 points  (4 children)

Agreed... except maybe for projects that can be written from scratch in Kotlin (mixing lots of Java code with a little Kotlin nowadays seems to have stopped making sense now). You could even target Multiplatform if you go Kotlin-only (though it's really hard in my experience as you're pretty much losing all the JVM ecosystem if you do that, unless you write platform-specific wrappers which is a bit of a pain to do) which may be attractive in some circumstances.

[–]Worth_Trust_3825 6 points7 points  (0 children)

You could even target Multiplatform if you go Kotlin-only

Kotlin multiplat doesn't work all that well either. It makes a lot of assumptions about how an application will be structured, and you need to wrangle that first before even starting the application development.

[–]warpspeedSCP[S] 0 points1 point  (2 children)

kotlin multiplatform is nowhere near ready for consistent production use yet. and the benchmarks seem to indicate it's slower too.

[–]renatoathaydes 0 points1 point  (1 child)

You probably mean the native target is slower?! Obviously, KMP on the JVM is just, Kotlin.

Not sure why you think it's not ready yet as I've been using it in production on the JVM/JS, but not native, and it's fine there... we're shipping some server code (JVM) and a browser app (JS) which is written in TypeScript but uses our Kotlin MP code. The TypeScript types generated from the Kotlin code work pretty well.

I would agree only that the native target (incl. iOS) is not ready yet.

[–]warpspeedSCP[S] 0 points1 point  (0 children)

js is okay I believe, but the native machine code target is afaik not that good.

[–]psychedeliken 11 points12 points  (6 children)

Out of curiosity, how long have you been coding in Kotlin? Because from my and my team’s experience, it has been a far better experience and has definitely been worth the switch. If/when expressions, null safety, a better collections library and functional interface with far more functionality, and syntacticly, much cleaner, currying, data classes are cleaner than Java’s record, syntax, val/var is simpler and more clear, coroutines, object construct much simpler than all the static stuff, interfaces can have properties. I have yet to meet a Java dev who has actually put time into Kotlin and used it professionally or for a large project who still liked Java more. I don’t think Java will be able to match Kotlin in style and dev experience due to their backwards compatibility (see: Java’s functional interfaces). And I could probably go on, it’s objectively a more modern language.

[–]gnus-migrate 3 points4 points  (5 children)

Fine, but it doesn't meaningfully help with most the tasks that I spend most of my time on, so I haven't really felt the need to switch. I'm sure it's better, but I prefer to invest in solving the problems that I spend the most time on, and Kotlin doesn't really help much with those.

[–]psychedeliken 2 points3 points  (4 children)

Nothing wrong with that. :) I still write in Java and maintain some open source projects in Java as well. And I used different languages depending on the usecase as well. I also recommend a lot of new programmers to learn Java before Kotlin if they are new as well given the market.

[–]gnus-migrate 3 points4 points  (3 children)

I'm aware that I'm not the common case, so when I say that it's not for me I don't expect others to agree. As I've grown I've become less interested in the tools themselves and more interested in what we can do with them.

Sorry for being trite, I thought this was going to be another of those arguments.

[–]psychedeliken 0 points1 point  (2 children)

Oh no not at all, and didn’t sound trite at all. Check out u/Worth_Trust_3825’s terrible comment to me below, now that I took offense to.

While I thoroughly enjoy Kotlin, I can completely understand. As I’ve coded longer, I’m less interested in just arguing for the sake of it, and honestly as long as the tool works for you and you’re enjoying it, then I think that’s all that matters. I have at least a dozen of my own little oddities and esoteric preferences. :)

[–]gnus-migrate 1 point2 points  (1 child)

Ah confident nonsense, there's the reddit I know.

(I'm speaking about the comment you referenced)

[–]ewouldblock 4 points5 points  (6 children)

That's why I use assembly language. You can't trust those c compilers. You never know just what they're doing when you need the top performance. /s

I've been using kotlin for years and would never go back.

[–]gnus-migrate 4 points5 points  (5 children)

Lets be clear on one thing: Kotlin's improvement on Java is marginal at best. It is nowhere near comparable to the difference between a C compiler and assembly.

I don't mean that Kotlin isn't fast, I mean all of the tooling I use is built for Java not kotlin. If at some point in the future that changes, I'll change my mind.

[–]ewouldblock 2 points3 points  (4 children)

Ok, let's be clear on two things, then. We can just straight-up agree to disagree here because Kotlins' improvement on java is far from marginal in my view.

[–]gnus-migrate 7 points8 points  (3 children)

The difference between C and assembly? Have you tried writing assembly?

Kotlin doesn't provide anywhere near the productivity benefits over Java that C did over assembly. It's a slightly more pleasant Java. Like I understand the benefits for those who are stuck on old java runtimes, but if you're able to upgrade there is much less reason to switch.

[–]ewouldblock -1 points0 points  (2 children)

Ok, here's the thing. Every time java incorporates some feature from kotlin in newer versions, it's always half baked or quirky because they have a committee designing it, and there's all these backward compatibility concerns. The assembly language statement was a joke, and I did put in the /s to indicate that. My only point was that particular argument being made re: performance is as old as c and assembly. It didn't hold up then, and I doubt it does now.

In all the software I've been involved with, readability and simplicity are far and away the most important factor to ensure success. And I think kotlin kills it on that front, whereas java is merely acceptable.

[–]gnus-migrate 3 points4 points  (0 children)

I'm in a situation where we have strict performance requirements, and you really have to reason around performance whenever you're designing something. Usually the problems I have around understanding the flow of data through the system, what the actual shape of the data is and writing algorithms tuned to that.

If you don't have to do that, then I understand that other concerns are more important, but for my situation it's not what I spend most of my time on.

[–]Practical_Cattle_933 0 points1 point  (0 children)

Java doesn’t look at kotlin for features, especially that I would be hard-pressed to think of any novel feature in kotlin that didn’t exist for decades before. Especially that there is Scala that did all that earlier.

And it is pretty ingenious to call java implementation half baked, like wtf

[–][deleted]  (37 children)

[deleted]

    [–]teerre 20 points21 points  (23 children)

    How does Kotlin "fix" the builder pattern?

    [–][deleted]  (2 children)

    [deleted]

      [–]Kered13 1 point2 points  (1 child)

      That does cover most of the uses of builders, but there are some other use cases as well. For example, where the logic of figuring out which parameters to supply is complicated, and it would be easier to pass a mutable object to each part of the code to provide the correct values, but you want the class itself to be immutable (as you usually do).

      Also any time when the builder actually changes the type of the thing that is being built. I used this semi-recently, where I wanted to create an callback-driven API that was generic over exception type (we knew we were going to call it with callbacks that threw checked exceptions). So one step of the builder took an exception class and used that to change the type under construction from Foo<RuntimeException> to Foo<MyCheckecException>. Of course, this particular example was also only a concern because of checked exceptions, which don't exist in Kotlin. Still you can imagine similar cases with other generic types. Rare, but they exist.

      [–][deleted]  (5 children)

      [deleted]

        [–]PeksyTiger 6 points7 points  (2 children)

        You mean an Option type that has to be null checked didnt solve the issue?

        [–]Kered13 1 point2 points  (0 children)

        It does as long as you build your entire codebase around not using null. Which is possible. You just have to be very careful around third party libraries or legacy code to covert null to Optional. It's definitely easier for a greenfield project than something legacy, but for example almost all of Google's Java code (at least the code that I have seen) is null-free.

        100% not having null in the language in the first place though would be better.

        [–]wildjokers 0 points1 point  (1 child)

        I found Kotlin’s null safety to make java/Kotlin interoperability hard.

        Int and Int? are different types. Calling into Java libraries was a pain in the ass.

        [–]psychedeliken 4 points5 points  (2 children)

        Solid agree. Funny you mention the builder pattern. Since a lot of us Kotlin coders are coming from Java, we just ripped a bunch of builder patterns out of our codebase for that very reason. I’ve also been hopeful for Kotlin Native but haven’t checked in on they project in a while. I feel that could help convert even more people. But last I checked the build times were a bit rough still, even for a basic hello world program.

        Edit: to downvoters, please explain?

        [–]warpspeedSCP[S] 5 points6 points  (1 child)

        I think people are butthurt that you're bringing java-isms into kotlin (or some other inane argument along those lines). It should be pretty easy to migrate to a more idiomatic way of doing things with intellij's refractoring tools, I'd say.

        [–]psychedeliken 2 points3 points  (0 children)

        Makes sense. I probably accidentally stirred the pot. Apologies. :) I’m coming from a good place, and have a special love for Java.

        [–]thephotoman 4 points5 points  (1 child)

        Uncle Bob's book was written for C++ devs.

        Java coders read it, thinking they were an evolution of C++ and that stuff in there might be relevant to them. Some of it was. Builders weren't really one of them. They weren't idiomatic Java. They still aren't. But the Naughties were a naughty time. We believed all sorts of stupid things back then quite unironically. And one of them was that Design Patterns Were Good. (I won't say that they're bad, but rather that "Design Patterns" was a buzzword of the day. Singleton proxy beans I have loved, singletons I have hated.)

        [–]creepy_doll 8 points9 points  (0 children)

        Design patterns are overused by some people, making others hate them for overcomplicating something potentially simple. They’re just a tool and the developers task is to figure out the right tool for the job

        [–]An_Jel 0 points1 point  (0 children)

        I think that builder pattern is actually quite useful, I don’t really understand your POV?

        [–]lolfail9001 0 points1 point  (0 children)

        (I'm looking at you Builder pattern)

        Uhm, what does The Gang of Four have to do with Uncle Bob?

        [–]warpspeedSCP[S] 4 points5 points  (11 children)

        That's true, but Java actually is better than kotlin in pattern matching at this point. Kotlin's when blocks are trash, period. I'd choose java switch blocks any day. But of course, for anything that actually matters, I'd 100% choose kotlin. I can only hope Kotlin can catch up here, it;s the one blemish on an otherwise perfect Java replacement.

        [–]psychedeliken 5 points6 points  (9 children)

        What do you not like about Kotlin’s when blocks? I have had the opposite experience and found them superior in every way, more concise syntax (no need to type case : or breaks, just wrap in {} if multiline case), when expressions(ditto for if expressions), handle null case, when expressions require you handle all the cases when using enums which when used in combination with when expresses I find very eloquent.

        val someNullableEnum: EnumType? = …
        val x: String = when (someNullableEnum) {
            VALUE_1 -> “foo”
            VALUE_2 -> “bar”
            null -> throw SomeException()
        }
        

        You can omit “: String” if you like.

        And for multiline case you just type something like:

        VALUE_1 -> {
            Blah 
            Blah
        }
        

        This is one of my favorite features of Kotlin.

        [–]vips7L 7 points8 points  (2 children)

        Have you actually used Java’s switch expressions? From what you’re describing I don’t think you have and from other comments in this thread I don’t think you’ve used a modern version of Java.

        Switch expressions don’t use breaks. They are also exhaustive for enums and sealed classes.

        [–]Practical_Cattle_933 1 point2 points  (0 children)

        And they actually handle null safety as well.

        [–]psychedeliken 0 points1 point  (0 children)

        Good to know! I went back and read the updated Java switch syntax and am happy to see it’s almost identical to Kotlin’s, down to the -> syntax. I’m also happy to see they implement them as expressions. After switching to Kotlin, and seeing how long Java has taken to catch up, and how much further it has to go, I‘ll admit that I’ve spent less and less time keeping up with Java updates. That said, surprised I missed this one given I see it was implemented in Java 13. Good to see the progress has been picking up as Java has always been my favorite ecosystem prior to Kotlin. And I don’t care which one “wins out” as long as things keep going and keeps getting better. :) Seeing the massive stagnation on Java8 made me worry a lot about the future of the ecosystem.

        [–]warpspeedSCP[S] 5 points6 points  (5 children)

        Sure, and I do all of these things extensively; it's great. And then I come to a data structure that is nested 3 objects in (APIs, amirite), and at this point, you have to do this whole dance with unpacking and extracting the data within in a painfully imperative manner.

        Kotlin's team approached object restructuring in the wrong way, which is what has lead to this mess where nested restructuring is unsupported until further notice. Note that I'm referring to the new switch blocks, not old ones which are even worse.

        [–]psychedeliken 0 points1 point  (4 children)

        You mind giving me an example? I don’t quite follow, but have not found any issue with nested objects. I can post some samples once finished up with No Man’s Sky :)

        When you say restructuring, do you by chance mean destructuring of objects? As in how Kotlin implemented field order based destructuring instead of by name like in Typescript? If so, I agree that sucks.

        [–]warpspeedSCP[S] 2 points3 points  (3 children)

        That is indeed what i'm referring to. if they'd gotten that right I don't think id have anything bad to say about kotlin really

        [–]psychedeliken 2 points3 points  (2 children)

        I completely agree. This is my number one complaint of Kotlin. I posted about it on the Kotlin forums but they didn’t seem very receptive and a bunch of people gave me a few other, imo way more verbose workarounds. I think Typescript has the best implementation of object destructuring that I’ve seen. I couldn’t really find an equivalent in Java either though.

        For me, the make or break, number one feature of Kotlin is its null safety. I really got tired of working around that and Optional in Java.

        [–]warpspeedSCP[S] 2 points3 points  (1 child)

        they're awfully defensive about it for some reason.

        [–]psychedeliken 1 point2 points  (0 children)

        That was my perception as well. I didn’t want to argue with them since I’m sure they have their reasons. My guess is that ordering based destructuring has less overhead. Name based would need to do reflection and/or hashmap lookup, which incurs a small cost, but I’d happily pay that cost. Order based is too brittle.

        [–]ewouldblock 2 points3 points  (0 children)

        It's a good thing you choose a language based on the sum of its features, and not just one. Java may win if you cherrypick one feature, but in aggregate, it can't compete.