Live data from Hacker News

From Java to Kotlin and Back Again

allegro.tech

181–190 of 199 posts

Re: From Java to Kotlin and Back Again

#181
post #134

Earlier quoted context omitted.

> Re immutable: If you're doing functional why does this matter? "true" immutable vs. just an immutable view should only matter if the object is retained by the function it's passed to, but now we're talking object state rather than pure functions. For the same reason that being able to write val rather than var matters. With perfect discipline you can write pure functional code in any language, but in practice (and…

For the same reason that being able to write val rather than var matters. With perfect discipline you can write pure functional code in any language, but [...] Strongly agree with you there. This is one of the main gripes I've got with many languages. People just have a "well don't do it" attitude and refuse to see the benefit in the possibility of forbidding mutation. A very important point here is the realization t…

If you truly need an immutable list there's no shortage of them available. It's more a "is this such a strong, common need that everyone must have it?"

So far I've never needed guaranteed immutability, I've just used kotlin's List (which is an immutable view). If that's the only thing anyone gets then it's functionally guaranteed immutable even though it's not sitting on an immutable implementation.

Re: From Java to Kotlin and Back Again

#182

Earlier quoted context omitted.

typealias MustBeInTransaction = MyTransaction.() -> Unit fun makeObject(i: Int): MustBeInTransaction { return { /* do something with i or whatever in a transaction */ } } fun test() { var genericArray = arrayOf(1, 2, 3).map { makeObject(it) } //genericArray.forEach { it() } // fails to compile transaction { genericArray.forEach { it() } } } Like that?

It is interesting to see that is possible in Kotlin. I just learned a lot about receivers (as an aside, do you know where I can find better documentation? The best I could find was a stack overflow post). I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers…

> as an aside, do you know where I can find better documentation? The best I could find was a stack overflow post

https://kotlinlang.org/docs/reference/type-safe-builders.htm...

It's more designed to build DSLs or similar, so you'll find more documentaion/examples in that area of the docs.

> I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers, async/await, try/catch, if(null)). Is there some way to do this all with receivers? It seems like they don't really compose.

It's just a closure with a compiler-added paremeter. It can be nullable if you want and exceptions work the same as any other closure. If you want async/await you'd use coroutines. I think coroutines and receivers mix just fine, you'd just make the type a suspending lambda with receiver, but I've never tried.

Re: From Java to Kotlin and Back Again

#183

Earlier quoted context omitted.

It is interesting to see that is possible in Kotlin. I just learned a lot about receivers (as an aside, do you know where I can find better documentation? The best I could find was a stack overflow post). I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling? It seems like you have to combine 4 different mechanisms in order to do this (receivers…

> as an aside, do you know where I can find better documentation? The best I could find was a stack overflow post https://kotlinlang.org/docs/reference/type-safe-builders.htm... It's more designed to build DSLs or similar, so you'll find more documentaion/examples in that area of the docs. > I think this issue with this is what happens when you combine DB transactions with async queries with errors and null handling?…

> https://kotlinlang.org/docs/reference/type-safe-builders.htm.... > > It's more designed to build DSLs or similar, so you'll find more documentaion/examples in that area of the docs.

Thanks for the link. However, I feel like that still doesn't give a lot of detail. Can you have multiple receivers? Can receivers be generic? Can receiver resolution be controlled by other arguments?

> It's just a closure with a compiler-added paremeter. It can be nullable if you want and exceptions work the same as any other closure. If you want async/await you'd use coroutines. I think coroutines and receivers mix just fine, you'd just make the type a suspending lambda with receiver, but I've never tried

Sorry I didn't mean to imply that Kotlin was incapable expressing all of these things together. I meant it would be desirable to express all of these things with the same tools. It seems like the you would have to express these with several different paradigms and be aware of how they interact. That also means you would need more boilerplate because you have to abstract each of these things separately.

Re: From Java to Kotlin and Back Again

#184
post #130

Earlier quoted context omitted.

> If it's a full new language, to be evaluated as a full language, then why would you adopt it when it's missing important features compared to Scala? For all the features it has that Scala doesn't of course, many of which may not be part of the core language (compile times, tooling, backing, simplicity, compile-time null safety, coroutines, quality native compilation, Android support, etc).

The claims about null-safety are pure FUD; once you get past thinking about the literal string enn-you-ell-ell, Kotlin and Scala are exactly as null-safe as each other in all the ways that matter (e.g. as shown in the article, Java interop in Kotlin has exactly the same null-safety issues as in Scala).

Java interop in well-designed Kotlin or Scala is pushed to the edges of the application and fenced off. Kotlin makes null safety a much more practical proposition at that point where Scala doesn't. To be frank, Kotlin's null-handling is one of the bigger reasons I think lesser-skilled developers should use it over Java.

And Scala's is good enough, but it's not as good as Kotlin's. Scala has plenty of other beams in its eye to deal with before getting on anybody else, though (this week's shitfire: developers thinking implicits are a good idea, much as it's been for the last five years...).

Re: From Java to Kotlin and Back Again

#185
post #28

Java version in the article: public int parseAndInc(String number) { return Optional.ofNullable(number) .map(Integer::parseInt) .map(it -> it + 1) .orElse(0); } And the Kotlin equivalent... "No problem one might say, in Kotlin, for mapping you can use the let function: fun parseAndInc(number: String?): Int { return number.let { Integer.parseInt(it) } .let { it -> it + 1 } ?: 0 } Can you? Yes, but it’s not that simple…

> fun Int?.orElse(fallback: Int) = this ?: fallback

Or even better:

    fun  T?.orElse(fallback: T) = this ?: fallback

Re: From Java to Kotlin and Back Again

#186
post #10

A number of valid points, but I'm not convinced by most of your critique of Kotlin. Colon between names and types (as in "i: Int") "makes work in Kotlin harder" ? Seriously? By as much as having to end lines with semicolons in Java? : ) I understand it's a matter of habit, but how could that possibly make anybody's work hard is beyond me "I can’t imagine a valid use case for shadowing a method argument." Arguably thi…

That GsonBuilder example is also screaming for an extension function like so: inline fun GsonBuilder.registerTypeAdapter(adapter: Any) = this.registerTypeAdapter(T::class.java, adapter) Bam, now it'd be: val gson = GsonBuilder().registerTypeAdapter (LocalDateAdapter()).create()

[deleted]

Re: From Java to Kotlin and Back Again

#187
A comment I posted on that blog post, that likes to keep going to spam box.

1. Name shadowing is a compiler warning. It is good to pay attention and clear all warnings by resolving the issues. It isn't a secret when you name shadow, and a developer I would hope would pay enough attention to not do it on accident. I've used Kotlin since 2013 and don't think I've shadowed a name even one time on accident. There is an issue in the Kotlin tracker to allow turning specific warnings into errors, this would give you the behaviour you want once added.

2. Kotlin type inference is the best out there, nothing compares in accuracy and scope. You aren't getting the same thing from Java 10 that Kotlin has by far.

3. Compile time null safety is accurate from Java libraries if they inform as to their null safety, for example there are many libraries that use `@NotNull ` and `@Nullable ` annotations and Kotlin respects and enforces those. They also handle this for JDK calls so that all standard library calls are correctly interpreted. You can fix your own custom Java libraries which also helps with Java static analysis. And eventually you'll use more and more calls to your own Kotlin code or to Kotlin libraries and you'll really be glad all of this null safety is there and part of the compiler.

4. Class literals are many times not used in Kotlin API design. Instead you as an API designer would just write an extension function that reifies the generic parameter and auto infers the class literal. Or you can do it yourself to extend any API you wish. You will only do that once and then enjoy the magic a thousand times after. There are actually modules for things like Jackson and GSON that do this already. So then the syntax is better than the Java because you don't have that parameter at all (which is type erased whereas reifying the full generic type is not). Here is an example of Java vs. Kotlin using Jackson object mapper in the same use case you were demonstrating:

Java:

  final MyStateObject state = mapper.readValue(json, MyStateObject.class)  // type erased, which sometimes is ok
  final List states =  mapper.readValue(json, new TypeReference>()); // not type erased
 
Kotlin:

  val state: MyStateObject        = mapper.readValue(json) // not type erased
  val states: List = mapper.readValue(json) // not type erased
 
Alternative Kotlin:

  val state  = mapper.readValue(json)       // not type erased
  val states = mapper.readValue>(json) // not type erased
 
Isn't type inference wonderful? Especially with reified types making API's like this possible.

5. Type declarations in the form of `name: Type ` are by design to allow for unambiguous syntax which keeps the language smaller and leaner than the C style typing which cannot be used everywhere without extra cruft to delimit what is going on. Plus this is more readable when scanning variable declarations since they are at a fixed position from the left instead of a random position on the right. Here are some good reading for you that let you know the Java style `Type varName ` is actually the less common across languages: https://softwareengineering.stackexchange.com/a/311739/20888... and then this post about how it interferes with higher level concepts in language to have it backwards as Java does: https://softwareengineering.stackexchange.com/a/311730/20888...

6. Companion objects are there so they can be extended, including with extension functions. You can easily do things like logging using other models and delegates instead of adding a companion object. Your logger system likely caches the logger by the way so having a reference on the object is not a huge item to add. You can also have a `main()` as a top level function and is not required to be in a class which probably makes more sense for a main anyway.

7. Collection literals are not present in Kotlin because in the JVM developers are more specific about the exact type of collection they wish to construct, and there are simple helper functions which make things clearer. The `: ` being used for maps would overuse that symbol and cause it to have different meanings (I think you complained about two uses of `: ` then you later suggest a third). What is wrong with `to ` for creating a pair which is used to create the map? it is an extension function, highly readable, and you can actually make your own with some other name (other than `: `) `to ` isn't part of the language syntax nor forced upon you. The Groovy syntax is bad because it looks like you are declaring a list/array. The other syntaxes don't say whether the maps are readonly or mutable and that is important in Kotlin. It is a carefully thought through issue.

8. Maybe? is not needed as much due to alternatives and null safety. But, there is the JDK Optional which you are showing and can just as easily be used by Kotlin as well. And more "native" versions in open-source Kotlin libraries. Kotlin just doesn't have one in its standard library, nor does it need one. I personally dislike API designs that force optionals on me for everything, so I'm glad Kotlin doesn't.

For your example code, why are you using Optional for this case of `parseAndInc `? Kotlin has the `?. ` safe operator to continue a chain when not null, and the `?: ` Elvis operator to provide a fallback on null values. Any operator like `+ ` is also available from its operator function (i.e. `plus() `) or in this case simply `inc() `. Therefore:

Kotlin:

  fun parseAndInc(possibleNumber: String?) = possibleNumber?.toIntOrNull()?.inc() ?: 0
 
Yet you can also write the same Kotlin code as your Java example (and slightly less typing):

Also Kotlin:

  fun parseAndInc(number: String): Int {
    return Optional.ofNullable(number)
        .map(Integer::parseInt)
        .map { it + 1 }
        .orElse(0)
  }
 
Compared to your Java:

  public int parseAndInc(String number) {
    return Optional.ofNullable(number)
                   .map(Integer::parseInt)
                   .map(it -> it + 1)
                   .orElse(0);
  }
 
Please remember that everything you can do in Java you can do in Kotlin including using all those Java classes you are familiar with. But, you can also learn idiomatic Kotlin and write it differently. This is one of the reasons the learning curve is very low.

9. Data classes, so you aren't complaining here or are you? You can't inherit the equivalent in Java either, you would have to rewrite `equals `, `hashCode `, `toString ` and more if you did that and each would need to be customized. So Kotlin has the same issue, inheritance of these is dangerous because manual decisions need to be made in order to do so. You CAN inherit from another class, and you could use composition and interfaces instead. Data classes are a life saver in code, covering a huge number of cases without all the boilerplate of manually coded JavaBeans.

10. Final classes by default are a good thing, and this has been heavily researched and talked about in the Java community as a best practice. Some old Java libraries do not know how to handle this because they don't expect it to be a problem. But those libraries are changing, and complier plugins for these libraries already help you out with 0 effort in changing code. Plus, newer libraries deal with this without problems. If you want to modernize, you have to modernize and not just expect new things to continue with allowing bad habits because some legacy code doesn't do things elegantly. I can't think of any blocking case related to this. It was well known, well covered, and is a non-issue.

11. Shallow learning curve. Kotlin is small language, consistent, and elegant. It does NOT have a steep learning curve. It is no where near Scala in terms of effort and complexity, yet you lump it in there anyway. Plus, isn't it worth learning a language over a week that'll save you 40-50% the lines of code, automatically eliminate whole categories of bugs you write, be many times more readable and maintainable? Kotlin is a few days to a week for an ex Java developer to write reasonable code, and then later they'll write more elegant code over time.

And about Spock vs. Spek: You don't have to pick either/or, since you can use Spock from Kotin too like any other Java library.

Re: From Java to Kotlin and Back Again

#188
post #62

The biggest red flag IMHO with Kotlin is the teams disinterest in supporting the language server protocol. They are taking a very insular approach to the ecosystem just like Microsoft used to with .Net. The world has moved on a bit from that mindset, but they are completely happy with coupling the experience to their companies IDE...

There isn't disinterest, there are priorities. And this is low on the list for the core team compared to the long list of high priorities. There is the whole playground codebase that anyone (you?) could use to handle the language server protocol.

It is a shame some people are disinterested in helping out. The Kotlin team can only do so much on their own...

Re: From Java to Kotlin and Back Again

#189
post #169

I've said it earlier, I am saying it again. "Kotlin enthusiasts or rather PR representatives cannot stomach criticism", this is quite visible on the blog itself and here on HNews. Consult with your CEO, CTO and/or Director of Engineering before switching to Kotlin, there may be things you might not be aware of, think 20 years ahead and think objectively about the pros/cons before heeding to advice of the enthusiasts,…

I'm a Kotlin enthusiast (since 2013) who has also used Java since 1995 and was quite the enthusiast for many of those years, tracking the progress of Java in detail since inception. I've contributed to both languages. Just so you are aware of my background being strong in both.

Now back to this blog post and enthusiastic defence of Kotlin:

This blog post wasn't a criticism, it was instead under-informed and misleading. You will indeed attract the attention of enthusiasts if you take an authoratative viewpoint against the thing those enthusiasts care about, publish it publically, promote it to the whole community, and use bad (or no) evidence in the process. Who wouldn't stand up and protect something they care about in that circumstance?

By the way, when we were helping to create Java at Borland, we were told many things like you just said: "it will fail", "the CEO/CTO/CIO won't want it", "we can't take the risk", "in 20 years it will be gone", "it's just a toy and not for the enterprise", "dancing Duke is all it can do", "it will fail like the others, Java is no exception", "no real application will be written in it", "it can't do server-side", "stick with C++", "stick with Delphi", "stick with VBA", "stick with PHP"

So obviously the prognosticators and non-enthusiasts were wrong. What makes you better are reading the future than they were? Is Google wrong when backing Kotlin? Is JetBrains? Is Square? Is the Spring Team? Is the Gradle team? Is the JUNIT team? Or are these some of the same people who made the right call on Java way back in 1995-2000 as well? In fact Java would have failed had the enthusiasts not carried it through tough times, shaped it up, improved performance, fixed critical bugs, cleaned up bad specifications, and showcased it to the world. Because of enthusiasts, you have Java.

So let the enthusiasts do their work of defending a good thing against people that just don't yet see the light (or maybe never will care to, so bet it).

Re: From Java to Kotlin and Back Again

#190
post #177

The particularly funny thing is how the blog admin - the author himself? - censors comments not to their liking, marking them as spam : ) They clearly are a bit touchy. Below, the comment he's deleted twice; you be the judge :) (I wouldn't normally repost, but the first time round I erroneously assumed it was due to including a link in it; apparently not). ---- The article has been commented extensively on Hacker New…

That forum (disqus) is very very bad at spam detection. And hates links in posts.
Post reply on HN