Skip to content

Instantly share code, notes, and snippets.

@GavinRay97
Last active August 10, 2023 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GavinRay97/9136a4c6f859a5a4943d04024f626f01 to your computer and use it in GitHub Desktop.
Save GavinRay97/9136a4c6f859a5a4943d04024f626f01 to your computer and use it in GitHub Desktop.
Kotlin wishlist

The 4 things I wish Kotlin had (as a Kotlin + Java + Scala developer)

Union types

We have sealed and can get by with this, but compare the following Scala 3 to Kotlin:

def parseNumber(number: String | Int | Float): Int = number match {
  case s: String => s.toInt
  case i: Int => i
  case f: Float => f.toInt
}
sealed interface Number {
    @JvmInline value class StringNumber(val value: String) : Number
    @JvmInline value class IntNumber(val value: Int) : Number
    @JvmInline value class FloatNumber(val value: Float) : Number
}

// Ignore that you could just overload "parseNumber()" please, it's an example
fun parseNumber(number: Number): Int = when (number) {
    is StringNumber -> number.value.toInt()
    is IntNumber -> number.value
    is FloatNumber -> number.value.toInt()
}

Collection literals, like Groovy:

def list = [1, 2, 3]
def map = [a: 1, b: "foo", c: true]
val list = listOf(1, 2, 3)
val map = mapOf("a" to 1, "b" to "foo", "c" to true)

Native Tuples

Example: val x = (1, "foo", true, 3.14)

Removed prior to 1.0: https://youtrack.jetbrains.com/issue/KT-2358/Drop-tuples

Destructuring-assignment and guards in pattern-matches for when:

Removed prior to 1.0: https://youtrack.jetbrains.com/issue/KT-2359/Drop-complex-patterns

Take this example possible in modern Java and Scala:

class SimplifyZeroPass {
    public static Expr simplify(Expr expr) {
        return switch (expr) {
            // x + 0 = x
            case Add(Var(var name), Const(var value)) when value == 0 -> new Var(name);
            // 0 + x = x
            case Add(Const(var value), Var(var name)) when value == 0 -> new Var(name);
            // x - 0 = x
            case Sub(Var(var name), Const(var value)) when value == 0 -> new Var(name);
            // x * 1 = x
            case Mul(Var(var name), Const(var value)) when value == 1 -> new Var(name);
            // 1 * x = x
            case Mul(Const(var value), Var(var name)) when value == 1 -> new Var(name);
            // x / 1 = x
            case Div(Var(var name), Const(var value)) when value == 1 -> new Var(name);
            // 0 / x = 0
            case Div(Const(var value), Var(var name)) when value == 0 -> new Const(0);
            // Otherwise, just return the expression
            default -> expr;
        };
    }
}

Writing this in Kotlin is more verbose and you lose the ability to visually group the patterns together:

fun simplify(expr: Expr): Expr = when (expr) {
    is Add -> {
        val (left, right) = expr
        when {
            left is Var && right is Const && right.value == 0 -> Var(left.name)
            left is Const && right is Var && left.value == 0 -> Var(right.name)
            else -> expr
        }
    }
    is Sub -> {
        val (left, right) = expr
        if (left is Var && right is Const && right.value == 0) Var(left.name) else expr
    }
    is Mul -> {
        val (left, right) = expr
        when {
            left is Var && right is Const && right.value == 1 -> Var(left.name)
            left is Const && right is Var && left.value == 1 -> Var(right.name)
            else -> expr
        }
    }
    is Div -> {
        val (left, right) = expr
        when {
            left is Var && right is Const && right.value == 1 -> Var(left.name)
            left is Const && right is Var && left.value == 0 -> Const(0)
            else -> expr
        }
    }
    else -> expr
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment