"Safe" use of Unit type


#1

I was faced with the fact that the implicit use of the type Unit is not always safe.
Below I give some examples, perhaps not all of them are perfect enough.

// Example 1. Use in expression
fun foo(x: Int, y: Int) {
    // do something 
}

// Can you guess while reading code that foo always Unit? What if foo changed in another module? Your code still compiles...
if (foo(1,2) == foo(2,1)) {
    println ("Yes")
}
// Same with a.equals(foo(1,2))
// Example 2. Branches

val f = {
   if (someCondition()) {
       42
   } else {
       // one of branches does not return value. Of course real code can be not so obvious
   }
}
// Example 3. Generics
class A <T,S>(val t: T, val s: S) 

fun foo(x: Int) {}

val a = A(foo(1), foo(2))
// Example 3. Vararg
fun foo(x: Int) {}

val a = listOf(1, 2, 3, foo(4))

… and so on
I think unintentional use of Unit in expressions can lead to hidden and late founded errors. But this only applies to infered Unit or generic types. So it can be useful to highlight such cases (with the code inspection for example).

This hypothetical inspection can be the following:

  1. Ignores explicit use of Unit (see below)
  2. Highlights any non-return and non-ignorable use of Unit in expressions.
  3. Highlights infered generic types with use of Unit
  4. Highlights places, where Unit can extend infered type.
  5. Quick tool to fix highlighted places by explicit type declaration
// examples of explicit use
val v: Unit = f() // OK
val a = listOf(1, 2, 3, foo(4) as Unit) // OK, but I'm not shure that this is good solution
val a : A <Unit,Unit> = A(foo(1), foo(2)) // OK

UPD: issue in tracker created - https://youtrack.jetbrains.com/issue/KT-17012


#2

So if I have this in Kotlin to say print a if is not null:

a?.let { println(it) }

Your proposal would mean that I am supposed to do this:

a?.let<Unit> { println(it) }

Not something I would want. I do that sort of thing with let all the time where I don’t care about the return value of let