oversolver's blog

By oversolver, history, 3 years ago, In English

Looking at language statistics in last rounds I have wondered why so many Java and so extremely low Kotlin coders?

Codeforces Round #797 (Div. 3)
CodeCraft-22 and Codeforces Round #795 (Div. 2)
Educational Codeforces Round 129 (Rated for Div. 2)

Kotlin, in a rough sense, is modern replace for Java, so...

If you are Java-coder then I am curious why you not change Java to Kotlin?

  • I'm too accustomed to Java/other, my brain think in Java, my hands do in Java
  • My (future) job is coding in Java
  • I doesn't like/hate Kotlin for some reasons
  • I don't want to note basic advantages of Kotlin which described everywhere. But it is language with modern syntax, and I think it is cool for cp almost as Python. I have more than one year experience of coding in Kotlin (but not cp!!), and I can describe my feelings as "I will never write even single line again in Java".

    Maybe you remembered Kotlin as not so cool language when it was 1.4 but now (1.7 in moment of writing this blog) both syntax and std lib have improvements. For example, instead of readLine()!! now it is readln(). Or modulo function

    val MOD = (1e9 + 7).toInt()
    println((-1).mod(MOD)) //1000000006
    println(((MOD-1L)*(MOD-2L)).mod(MOD)) //2
    

    Usage of lambdas in Kotlin is awesome. Just look at this custom comparator:

    data class Segment(val l: Int, val r: Int, val id: Int)
    ...
    segments.sortWith(compareBy<Segment> { it.l }
        .thenByDescending { it.r }
        .thenBy { a[it.id] }
    )
    

    Last what I really like is extensions, great for templates/libraries

    fun IntRange.firstFalse(pred: (Int) -> Boolean): Int {
        var l = first
        var r = last + 1
        while (l < r) {
            val m = (l + r) / 2
            if (pred(m)) l = m + 1 else r = m
        }
        return r
    }
    
    //usage:
    val i = (0 .. 2e9.toInt()).firstFalse {
        1L * it * it <= s
    }
    
    • Vote: I like it
    • +63
    • Vote: I do not like it

    | Write comment?
    »
    3 years ago, # |
      Vote: I like it 0 Vote: I do not like it

    Probably because Kotlin is waaay less popular than Java. Add to that the fact that the vast majority of universities teach Java/Python and not Kotlin, which skews the ratio Java:Kotlin even more in the young demographic.

    I assume most Kotlin users here are either older (working as SWE) or stumbled on Kotlin because of Android.

    »
    3 years ago, # |
      Vote: I like it +12 Vote: I do not like it

    well, I love kotlin, in fact, I have given a lot of contests in kotlin on codeforces and other cp platforms as well. Now, I don't use kotlin anymore because of the outdated kotlin versions on other cp platforms. Codeforces has the always maintained the latest versions of the language, so I don't have any problem writing modern kotlin code and submitting it on codeforces but I have to face a lot of problems when I write code in kotlin(some modern kotin syntaxes) and when I run it on let's say codechef, it simply gives a compilation error. The same goes for the leetcode as well. Now you can think of happening this midway through the contest. So that's why I had to come back to java, so that I could give contests on every platform.

    »
    3 years ago, # |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    I agree there should be more usage of kotlin. Maybe testers can provide solutions in kotlin ?

    »
    3 years ago, # |
      Vote: I like it +3 Vote: I do not like it

    Java is a lot more well-known and well-supported (for example, not all contests allow Kotlin).

    If you want to make the effort to move away from Java to something better, you'd probably switch to C++ instead (like I did, after many years of doing competitive programming in Java).

    »
    3 years ago, # |
    Rev. 2   Vote: I like it +23 Vote: I do not like it

    I don't understand how primitive types works in Kotlin. They say

    On the JVM platform, numbers are stored as primitive types: int, double, and so on.

    Well, first of all, I don't understand what that means. Let's assume it means something like "Int, Double etc. are equivalent to primitive java types". But then why do we need IntArray and the like?(and yes, I know the answer is that IntArray is int[] and Array<Int> is Integer[]).

    Now let's look at val MOD = (1e9 + 7).toInt(). How is this going to work? Which object is toInt() going to be invoked on? Or is it going to be optimized during compilation?

    If it's the former then all of this is kinda useless for CP. If it's the latter, it's very cool of course but kind of... opaque? Is this the case for every method of Int(Double)?

    All in all, many questions, almost no answers(or I can't be bothered to try and find them).

    • »
      »
      3 years ago, # ^ |
      Rev. 2   Vote: I like it +10 Vote: I do not like it

      About primitives, it may be helpful to read about inline classes. In fact, you can think about Int in kotlin as an inline class over primitive int from java. So rules are the same — it would be always primitive, except in cases where it is used as more generic types. Typically, there are three cases for that:

      1. Using is generic type (List, Array, and non-inline generic functions)
      2. Saving in Any variable, or function argument (e.g. passing to println)
      3. Using it as Int?.

      All of this is basically the limitations of jvm platform. You can't reasonably have primitive in any of them on java (at least until Valhalla project is done). In fact, that is a rule. If there is a reasonable way of having primitive in JVM — Int/Double/Long/Float would always be primitive.

      Probably, the only case against this intuition is Array, which follows common rules of generics, and is not optimized to Primitive[], while they can be on the first view. But things are more complex in touch with other features. The core problem is primitive is not a java object, so in fact, if Array would be int[] and not Integer[] it would be a corner case in all overload rules and etc. And I'm not even speaking about some types like Array<out Comparable<Int>> which should be able to store Array<Int>,

      Hiding details, which are not important, is one of the main ideas of Kotlin language. But "being not important" is quite a domain-specific thing. And this requires some experience to avoid performance penalties on wrong usages in different corner cases.

    »
    3 years ago, # |
      Vote: I like it +26 Vote: I do not like it

    As a man who competed in ICPC WF using Kotlin and developing things on Kotlin @ JetBrains, I have a few things to notice:

    1. Multi-dimensional DP might be hard, compare int[][][] a = new int[1][2][3] and val a = Array(1) { Array(2) { Array(3) } }, int[][][] and Array<Array<IntArray>>.

    2. When you're comfortable with map, filter and similar operations, you might fall in a pitfall when you for example want to iterate over a range of numbers (0..x) and filter them, map and so on. You may assume if will work just as fast as a usual for loop, but in reality it's much much slower, because Kotlin will collect those indices to a List first and then operate with lists, which is much slower than for loops even in Java.

    3. Sometimes you want to write for loops in c-style to have some custom break conditions or increment operations, but in Kotlin you can't. Just remember all those Fenwick trees, Iterative Segment trees (down to top for-loops), FFT and so on.

    4. Sometimes it's way too safe. You cannot have an array of nulls and work with it like in Java. In Java you can have State[] a = new State[n], in Kotlin you either have a nullable array val a = Array(n) { null as State? } or you hack the compile-time with ugly val a = Array(n) { null as State? } as Array<State>.

    By the way, Kotlin has lots of cool things such as nice syntax, data-classes, easy-looking lambdas, extension functions, local functions, operator overloading, inline classes and so on

    As for me, Kotlin is doing a great job in terms of replacing Java, and if I know that I can solve some problem on Kotlin, I'll do it. Otherwise I'll go with C++. Java becomes useless here. You either have a nice and debug-friendly Kotlin, or unsafe but fast asf C++.

    • »
      »
      3 years ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it
      1. Don't really think that this takes to much time on contest, as you need to print it only once, but maybe something like fun <reified T> array2d(a:Int, b:Int, init: (Int) -> T) = Array(a) { Array(b) { init(it) }} in your template can help you. It can be used as val a = array2d(1, 2) { IntArray(3) }, which probably can be wrapped to intArray3d helper if you wish.
      2. Take a look on .asSequence(). It's still would be slower then loops, as it leads to a lot of boxing/unboxing and iterators behind it, but already several times faster.
      3. Nothing to say here, except you can use while loops, which are often less convenient. Also, take a look at tailrec function, they help with some of the mentioned cases.
      4. There is arrayOfNulls helper function in stdlib. So your code can be written as `val a = arrayOfNulls(n)). Does it solve your problem?
      • »
        »
        »
        3 years ago, # ^ |
          Vote: I like it +3 Vote: I do not like it
        1. It does not take lots of time, it just looks ugly
        2. It'll still be much slower than a for-loop, but I'll try, thanks
        3. tailrec helps in several situations, that's true
        4. arrayOfNulls creates Array<T?> whereas if you have an array, you want to deal with Array<T>, this is what I meant. You still need a cast to an array of non-nulls.
    • »
      »
      3 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      I truly can't understand 4'th case. If array is non nullable, why it must contain nulls?

      • »
        »
        »
        3 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Usually, you don't want to create a non-nullable value just to put it in the array and never use it.

        In Java, you just write State[] a = new State[n], then it will contain nulls and you have to manually deal with it.

        In Kotlin, in order to have an array of non-nulls, you should either use a cast as in the comment above, or create and initialize the object inside: val a = Array(n) { index -> State(...) } which is not free and in most cases does not make any sense.

    »
    3 years ago, # |
      Vote: I like it +10 Vote: I do not like it

    btw, sparky_master_wch1126 also use kotlin