📜 ⬆️ ⬇️

Why Kotlin sucks

This article was born based on this article in the form of a half-joke. In that article, most of the “problems” are either synthetic and extremely rarely used, or far-fetched because of the expectation that the language is consistent with the theoretical paradigm of which, in the author’s opinion, the language should correspond. On the other hand, things that personally complicate my life are not mentioned.


Kotlin, . , , .


for


for Kotlin , Kotlin .


inline fun <T> For(it : Iterator<T>, cb : (T) -> Unit) {
  while (it.hasNext()) cb(it.next())
}

fun main(a : Array<String>) {
  val list = listOf(1, 3, 4, 12)
  println("for");   for (it in list) println(it)
  println("FOR");   For(list.iterator()) { println(it) }

  val arr = arrayOf(1, 3, 4, 12)
  println("a-for"); for (it in arr) println(it)
  println("a-FOR"); For(arr.iterator()) { println(it) }

  println("r-for"); for (it in 0..10) println(it)
  println("r-FOR"); For((0..10).iterator()) { println(it) }
}

For for, . , .


: ? .


, for-, . . , , - , while-.


- null-


- , , - , 25 , (sic!) void*, : " " " ". , . , , ?


null-safety Kotlin-, ? null , Java, Kotlin, , . , ? . , .


, . - - , ? null, . , Kotlin .


var value : Int? = null

fun F() : Int {
  if ( value != null ) return 0
  return value // 
}

Smart cast to 'Int' is impossible, because 'value' is a mutable property that could have been changed by this time . - - .


, ??!!! ? , — ? , - .


? ! . . . . , "" .


var value : Int? = null

fun F() : Int {
  if (value == null) return 0
  return when (Random().nextInt()) {
    3    -> value!! + 2
    12   -> value!! + 1
    5    -> value!! * 4
    else -> 0
  }
}

, "" , . , null — "" , .


null , . , " - ".


, .


Java


public class jHelper {
  public static jHelper jF() { return null; }
  public void M() {}
}

Kotlin


fun F() {
  val a = jHelper.jF()
  a.M()  //!
}

- , c NullPointerException .. Kotlin . ..., , ?


, :



.. , , . , !


.


— ?


if , , . ?


var value = 10

fun F() : Int {
  return value = 0 // 
}

:


var v1 = 1
var v2 = 1
var v3 = 1

fun F() {
  v1 = v2 = v3 = 0 // 
}

? , , . if (v=20)?.. , , .. , Kotlin, -, . . ?


"?:"?


"?:"?


?


value != 0 ? "Y" : "N"

if :


if (value != 0) "Y" else "N"

( ?) , if () else , .


?


, — . , , . , , . - ?! , ?


, . Pascal. - «there are no implicit widening conversions for numbers»? "are no", ?


val i = 10
val l = 12L
val f = 12.1

val l1 = i+100/l-f

?!


val l1 = i.toDouble() + 100.toDouble() / l.toDouble() - f

.. - … … - … … . — . , , Int Long, Float Double.


, .


:


val c : SomeClass? = null

if ( c ) "not-null"
if ( !c ) "is-null"

.. .


-typedef


Kotlin . . , , . — , … -.


- . :


  1. . , , - . .


  2. . .. . , .


  3. . . ( .1), .. , , () . .

:


typealias aI = SuperPuperClassA
typealias pSI = Pair<String,Int>
typealias pIS = Pair<Int,String>
typealias pOTHER = Pair<String,Int>
typealias aS = List<String>

class SuperPuperClassA {
  fun F() = pSI("",10)
}

fun main(a : Array<String>) {
  val a = aI()
  val i1 = a.F()
  val i2 : Pair<*,*> = a.F()
  val i3 : Any = a.F()

  //     
  if ( i1 is pSI ) println("ok")
  if ( i1 is pOTHER ) println("ok")

  //   
  if ( i1 is pIS ) println("not compile")
  if ( i2 is pSI ) println("not compile")
  if ( i2 is pIS ) println("not compile")
  if ( i3 is pSI ) println("not compile")
  if ( i3 is pIS ) println("not compile")
}

, . .. , . , Kotlin , ( ), , , .


, , : "Cannot check for instance of erased type". ( ) JVM.


.


, . - .


, , , ?


Nested and local type aliases are not supported


, , .. private "" .



(generics) Java Kotlin : JVM .


Java .. . Kotlin, , Java , , .


() - .. , .


:


/*00*/ class C<T>(val value : Any) {
/*01*/   fun F() : T {
/*02*/     try {
/*03*/       val v = value as T //  "Unchecked cast: Any to T"
/*04*/       return v
/*05*/     } catch(ex : RuntimeException) {
/*06*/       println("Incompatible")
/*07*/       //    ,        
/*08*/       return 0 as T
/*09*/     }
/*10*/   }
/*11*/ }
/*12*/ 
/*13*/ fun fTest() {
/*14*/   val a = C<Int>( 12.789 )
/*15*/   println( "rc: ${a.F()}" )
/*16*/ 
/*17*/   val b = C<Int>( "12.123" )
/*18*/   println( "rc: ${b.F()}" )
/*19*/ }

, "" .


, : ?


:


  1. , "12", "12"
  2. , "12", "Incompatible"
  3. , "12.789", "12.123"
  4. "C::F" ( ?)
  5. "fTest" ( ?)

: "fTest" 18


rc: 12

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
    at jm.test.ktest.KMainKt.fT(kMain.kt:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

: ?


  1. , Double Int?
  2. try/catch?
  3. "C::F"?

, .


, Kotlin "C::F":


// val v = value as T

GETFIELD jm/test/ktest/C.value : Ljava/lang/Object;
CHECKCAST java/lang/Object
ASTORE 1

( ), CHECKCAST Object . .. , .


, "C::F":


LINENUMBER 18 L6
ALOAD 1
INVOKEVIRTUAL jm/test/ktest/C.F ()Ljava/lang/Object;
CHECKCAST java/lang/Number

-, ( ), , . : Kotlin, , .


, Kotlin, .


: Java . , , , … — VCL. Borland -, Pascal RTTI, . , Java , Kotlin- . . , , , - , Java.


Java.


public class jTest<T> {
  Object value;

  jTest( Object v ) { value = v; }

  public T F() { return (T)value; } //  "Unchecked cast"

  public static void Test() {
    jTest<Integer> a = new jTest<Integer>( 12.123 );
    System.out.print( "rcA: " );
    System.out.print( a.F() );

    jTest<Integer> b = new jTest<Integer>( "12.789" );
    System.out.print( "\nrcB: " );
    System.out.print( b.F() );

    System.out.print( "\n" );
  }
}

Kotlin Java.


fun fTJ_1() {
  val a = jTest<Int>( 12.123 )
  println( "rc: ${a.F()}" )

  val b = jTest<Int>( "12.789" )
  println( "rc: ${b.F()}" )
}

fun fTJ_2() {
  jTest.Test()
}

: , :


  1. Kotlin;
  2. Java, Kotlin;
  3. Java;

?


:



:


  1. Kotlin:


    rc: 12
    Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

  2. Kotlin->Java:


    Exception in thread "main" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer

  3. Java:
    rcA: 12.123
    rcB: 12.789

? .



( Java, Scala, Groovy Lua , , ++) , .


Kotlin — , . ( ) : listOf, mapOf arrayOf.


, - :


  val iArr1 = arrayOf(1, 2, 3)
  val iArr2 = arrayOf( arrayOf(1, 2, 3), arrayOf(1, 2, 3), arrayOf(1, 2, 3) )
  val iArr3 = arrayOf(
    arrayOf(arrayOf(1, 2, 3), arrayOf(1, 2, 3), arrayOf(1, 2, 3)),
    arrayOf(arrayOf(1, 2, 3), arrayOf(1, 2, 3), arrayOf(1, 2, 3)),
    arrayOf(arrayOf(1, 2, 3), arrayOf(1, 2, 3), arrayOf(1, 2, 3))
    )

:


  val tree = mapOf(
    Pair("dir1", mapOf(Pair("file1", 0), Pair("file2", 1))),
    Pair("dir2", mapOf(
      Pair("dir21", mapOf(Pair("file1", 0), Pair("file2", 1))),
      Pair("dir22", mapOf(Pair("file1", 0), Pair("file2", 1))))) )

, - .


, ( JSON ), ...


  1. , — - ( ).
  2. , , .
  3. , , .

, — , .


: - . Array<Array<Array<Array<Double>>>> Array<Array<Array<Double>>> .


')

Source: https://habr.com/ru/post/322256/


All Articles