1. 13

  2. 11

    I can’t imagine a valid use case for shadowing a method argument.

    In OCaml I use shadowing all the time, since when I shadow a value, I make it impossible to access the previous value by accident. Especially if the type stays the same I never run into the problem where I accidentally pass num around where instead I meant to use new_num by the simple fact that the scoping just prevents me from messing up.

    First, you need to type and read this noisy colon between names and types. What is the purpose of this extra character? Why are names separated from their types? I have no idea. Sadly, it makes your work in Kotlin harder.

    Except for this being the accepted type annotation syntax in just about any modern typed language I might concede the point but then again, why does Java have all these { and }? I have no idea. Sadly, they make your work in Java harder.

    1. 3

      Yes, that’s how it works in Rust too: shadowing often replaces assignment (and you can even “change” type of the variable, that feels like a dynamically typed language!). To my surprise, this shadowing-as-usual makes me much more aware of shadowing and actually prevents shadowing bugs.

      1. 2

        I don’t know if Kotlin has it, but one thing that is useful for shadowing is a warning for if you don’t use a variable. In that case, the code provided would provide warnings because they don’t use one of the num’s.

      2. 10

        Quite a few of the things in this post are genuinely preferences (e.g. whether the type is before or after the argument, whether open classes are a good or a bad idea, whether data classes should…I guess not exist because they don’t work the way the author wants? I’m not clear what the point is), but some of them seem odd to me.

        First, in 2014/2015, when Kotlin was much less mature and well-supported than it is today, and when documentation was much scarcer, I oversaw a team convert several medium-sized Java applications to Kotlin. We did this at a company that had tried and failed to adopt Scala several times due to its complexity, and several people on my team had survived those attempts. But we were up and moving in Kotlin in a couple of weeks, and successfully converted everything within a couple of months—with quantitative improvements in crashes and performance (largely due to a pile of NPEs the compiler caught in the process and resource leaks plugged by Kotlin’s .use semantics). That would seem to explicitly challenge his claim that it’s as complicated as Scala, and that the interop with Java is a problem in practice.

        I also found their notes on companion/static objects odd. For example, “[o]ld good public static void main() is still the only way to launch a Java app,” which is true at the bytecode level, but in Kotlin, you’d normally just write top-level functions for that purpose. In fact, you can indeed do that for main itself: most Kotlin programs start with a simple top-level fun main(args: Array<String>). In fact, that’s literally the first block of code on the Kotlin home page. The reason for the companion objects is because statics in Java have piles of odd behaviors due to the fact that they are more global functions than genuine class methods, which is the exact reason companion objects exist in the first place: you can use them wherever an object would work, you can reasonably override methods, etc., and it’ll all work the same as it does for class instances. I.e., it’s simpler. Unless I’m misremembering, in our entire codebase, I’m not sure we had any statics, and we used the companion objects very rarely. Namespaced top-level functions and variables almost always took their place.

        Similarly, the note about the lack of a Maybe monad is weird. First, the particular example is nonstandard to the point it’s hard to use it as a discussion point; (number ?: "0").toInt + 1 or number?.let { it.toInt + 1 } ?: 0 are both shorter than either the existing Kotlin or Java versions, and easier to read as well. But Kotlin can also just use the Java monad, and if you want a real monad, people have written the Maybe monad in Kotlin. It might be nice if it were in Kotlin’s stdlib, but it’s not hard to get.

        There are a lot of reasons I can think of not to use Kotlin: you’re effectively tied to IntelliJ, compilation times are slower, Kotlin doesn’t really do SAMs, Kotlin makes it very difficult to figure out if you’re working with a primitive or not when you’re trying to write performance-sensitive code, etc. But most of the stuff in this article seems really does ring odd to me.

        1. 3

          Honestly, I don’t find much in this article that seems like I would not want to try Kotlin for a project. Maybe the interop with Java can be bad, but maybe it can be offset by other plus of Kotlin.

          The open class problem is something a lot of people complained in Java about class and variables are not final by default. I guess that the article is more like : I’m not agreeing with a lot choices that was made in Kotlin.

          1. 2

            Honestly, I don’t find much in this article that seems like I would not want to try Kotlin for a project. Maybe the interop with Java can be bad, but maybe it can be offset by other plus of Kotlin.

            The message I would take away is: Kotlin is not a lightweight extension to Java, it’s a complete language, and picking it up will require the same amount of effort as picking up another JVM language. You might find Kotlin offers enough to be worth that cost, but you should weigh its benefits against those offered by Scala, Groovy, JRuby etc.. Do not believe the hype that this is a new kind of JVM language with better Java interoperability than its predecessors; it’s not.

          2. 1

            I’m not a kotlin fan either, but many of the features they’re complaining about (like name: type instead of type name) are “consensus syntax” that most new languages use.