Home > other >  How NOT to return last expression's value from a Kotlin block?
How NOT to return last expression's value from a Kotlin block?

Time:10-27

I have a method that returns nothing. Inside it, there's a try-catch block:

override fun sendResourceCreationRequest(...) {
    try {
        val requestEntity = ...
        restTemplate.exchange(requestEntity)
    } catch (e: RestClientException) {
        ...
    }
}

Because the value of the last expression in a try block is returned implicitly, I get this compiler error:

Type mismatch.
Required: Nothing
Found: ResponseEntity<???>

I can assign the value to a variable and the error goes away:

val response: ResponseEntity<Unit> = restTemplate.exchange(requestEntity)

But now I have an unused variable which I (and lint) don't like. What's the best way to handle this?


Edit

The error went away when I specified the response type explicitly:

restTemplate.exchange<Unit>(requestEntity)

Perhaps something to do with exchange being an inline reified function or something?

@Throws(RestClientException::class)
inline fun <reified T> RestOperations.exchange(requestEntity: RequestEntity<*>): ResponseEntity<T> =
      exchange(requestEntity, object : ParameterizedTypeReference<T>() {})

CodePudding user response:

Firstly, I'm not 100% sure what is going on here, but I think you misinterpreted this case. This error has nothing to do with the return type of sendResourceCreationRequest(). Assuming the sample is (almost) complete, this function does not return Nothing, but Unit, so the error message does not make too much sense. Also, last expression is implicitly returned only in lambdas, but not in regular functions. Value of restTemplate.exchange(requestEntity) expression in this sample is not really returned, but simply ignored.

The problem is different. exchange() is parameterized and it requires to provide its T, so it could work properly. Both of these code fragments provide T:

restTemplate.exchange<Unit>(requestEntity)
val response: ResponseEntity<Unit> = restTemplate.exchange(requestEntity)

However, in your original code (restTemplate.exchange(requestEntity)) T is unknown.

Still, I'm not sure why you get error about Nothing and not that T can't be inferred. It may be somehow related to contents of inner exchange() function.

But anyway, the direct answer to your question is that you should use exchange<Unit>(). I'm just not sure if this will work for you as the REST framework may try to interpret the response as Unit which probably won't work. I don't know what is the REST library you use and what is your case exactly, but if you just need to ignore the response and if Unit doesn't work, you can try exchange<String>(). In many REST frameworks that means: "don't process the response body, return it as it is".

CodePudding user response:

The compiler states the error as Nothing has to be returned to the method sendResourceCreationRequest(), which means the signature of the method has to be like this:

abstract fun sendResourceCreationRequest(): Nothing

Check the definition of Nothing from below:

/**
 * Nothing has no instances.
 * You can use Nothing to represent "a value that never exists":
 * for example,
 * if a function has the return type of Nothing,
 * it means that it never returns (always throws an exception).
 */
public class Nothing private constructor()

Since sendResourceCreationRequest() has Nothing as return-type, this method will have to halt the further executions by throwing an Exception.

From the use-case point of view, if this is not the intended behaviour of the method, just remove the return type Nothing and replace it with Unit.

abstract fun sendResourceCreationRequest(): Unit // Explicit way of saying method won't return anything.

// OR

abstract fun sendResourceCreationRequest() // Implicit way of saying method won't return anything.
  • Related