Should unit function expression body produce missing return type error in explicit API mode

I have enabled the strict explicit API mode with the -Xexplicit-api=strict compiler option. While updating my API, I stumbled upon this error:

public fun foo() = Unit  // Error: Return type must be specified in explicit API mode

Correct usage would be:

public fun foo(): Unit = Unit

Whereas when not using expression body this is not required:

public fun foo() {}  // No error here, no need to use `fun foo(): Unit {}`

The use case is no-op default implementation for interface methods. I always preferred = Unit to {}, but now it’s just silly. Does anyone else thinks it would make sense to relax the return type rule for = Unit?

3 Likes

I’m not sure I like this idea. Why only Unit? The whole point of this type is that, unlike void, it isn’t special in any way. So why? Why not this:

public fun foo() = 0

for a default no-op implementation of an Int-returning function?

With {}, though, Unit is just the default return type, no matter what goes into {}. That makes sense because the return type is mandatory for that syntax, and if you omit it, you’re saying you don’t return anything.

So while I understand your reasoning, I fail to see a solution that would make enough sense.

public fun foo() = Unit

To be honest you shouldn’t really use this anyways. Why would you want a function that does nothing?
I guess this could be a simplified version for

public fun foo() = someOtherFunction()
fun someOtherFunction: Unit {}

But in that case the error is justified. After all -Xexplicit-api=strict is there to prevent you from changing the return type of a public function by accident (thereby breaking your API).

Obviously the OP was just a reductive example for a scenario where a single-expression function returns Unit. I hope we can all rationalize situations in which such a thing exists.

If the Unit return type would be the only type excluded from this check, then it would still prevent you from accidentally changing the return type.

consider we originally have the following function:

fun log(message: String) = PrivateLogger.log(message)

If Unit were exempt from the explicit API check this would be valid.

Say that we change the return type of PrivateLogger.log to a Boolean, indicating whether the line was logged or not. This would accidentally break our API:

fun log(message: String) /**:Boolean**/ = PrivateLogger.log(message)

But it wouldn’t, the compiler now sees an implicit return type of Boolean. Which, unlike Unit, does require explicit mention. Compilation would fail.

To be fair though, this error is way more subtle. A developer might think they merely forgot to specify the return type in the first place, or that they accidentally deleted the return type while refactoring.
Personally that’s reason enough for me not to support the proposal.

Yeah, I expected it was a simplified case (see second half of my awnser) but I m missed that an accidental change to the type would then casuse an error because now it’s no longer Unit and needs to be explicitly stated.

I don’t know. I feel like an “explicit” mode should be explicit. That said I can understand the OPs request. Also I don’t think there is much of a downside. Sure, you might be confused by why something is no longer compling, but most people use some kind of versioning that would clearly show that you haven’t changed the function, thereby implying that it’s an upstream change. And this is a simple rule to understand: "The type must be specified explicitly unless it is Unit". There is nothing confusing about it. Sure, you might take a few seconds to find out why the error is there after a change to an seemingly unrelated pice of code, but it shouldn’t be hard to trace.

1 Like