Discard return value to return Unit?

Viewed 2669

I am just starting with kotlin, so, forgive me if this is a basic question, I did do some googling, but that didn't turn up anything useful.

The question is how do I convert a value to Unit. For example, in scala, if I write something like this:

def foo: Int = ???
def bar(x: String): Unit = x match {
  case "error" => println("There was an error")
  case _ => foo      

}

The return type of the match expression is Any, but it is discarded by the compiler and Unit is returned by the function.

But doing something like this in kotlin:

fun bar(x: String): Unit = when(x) {
 "error" ->  println("There was an error") 
 else -> foo()
}

it complains about the foo part: inferred type is Int but Unit was expected

I know, that in this case, I can just get rid of the =, and put the body inside a block instead, that works, but I am looking for a general solution. What I was able to come with so far is just foo.let {}, but it seems kinda clumsy, especially if there are many cases like this where it needs to be done.

3 Answers

You can create an extension method on Any object and call it. I just prefer to use the name discard() rather than toUnit(), since I feel it conveys better the intent:

fun Any?.discard() = Unit

fun foo(): Int = 3

fun bar(x: String): Unit = when (x) {
    "error" -> println("There was an error")
    else -> foo().discard()
}

There's no way to do that out of the box, but you can make an extension function for this:

fun Any?.unit() = Unit

Then use it as:

fun bar(x: String): Unit = when(x) {
    "error" ->  println("There was an error") 
    else -> foo().unit()
}

Alternatively, make when a statement and not an expression:

fun bar(x: String) {
    when(x) {
        "error" ->  println("There was an error") 
        else -> foo()
    }
}

There are three solutions to your problem, which come to my mind:

  1. Make when a statement instead of expression, so its result does not get returned:

    fun bar(x: String) {
         when(x) {
            "error" ->  println("There was an error") 
            else -> foo()
        }
    }
    
  2. Use an extension to convert values to Unit:

    fun Any?.asUnit() = Unit
    

    Usage:

    fun bar(x: String): Unit =
       when (x) {
           "error" -> println("There was an error")
            else -> foo().asUnit()
    }
    
  3. Wrap the call into higher-order function call that returns Unit, e.g. with:

    fun bar(x: String): Unit = with(x){
        when (x) {
            "error" -> println("There was an error")
            else -> foo()
        }
    }
    
Related