Hi there, I'm having some issues because type chec...
# compiler
a
Hi there, I'm having some issues because type checking not working as expected, I have a generic function such as
fun <T> something(f: () -> T): T
and I would like for the compiler to fail if I try to do this:
Copy code
val unit: Unit = something {
    1 
}
The problem with this is that if we would have something like a Flow inside or any other complex type that we forgot to execute/unwrap/whatever, this would be a bug in the codebase, for example:
Copy code
val unit: Unit = something {
    flowOf(1)
}
If this would fail as I would expect it to, I would notice that I forgot to collect my flow, but instead is accepting a Flow or any type as Unit, is there a way to enforce this somehow?
w
You can try having a deprecated function with concrete
Unit
type, which would have precedence over non-unit variant?
Copy code
@JvmName("somethingReturningUnit")
@Deprecated(message = "Something must return a non-unit value", level = DeprecationLevel.ERROR)
fun something(fn: () -> Unit): Nothing = error("Shouldn't happen")
But you may have to explicitly declare typed arguments for non-unit usages 😕
a
also, I might not control such function 😅
w
If it’s a top-level function, you should be able to override it regardless. If it’s an instance method, then I’m not sure
a
in my specific case is a function from a library, but that's not the point I wanted to make, but to be able to enforce type checking
w
enforce type checking
type checking works as expected here, if a function returns
Unit
then the generic type resolves to
Unit
, and if you explicitly define the type as
Unit
that’s perfectly valid as well. My suggestion was to trick the compiler by making it pick an invalid function by utilizing the fact that a function with more concrete declaration (with an explicit
Unit
) will be picked over the generic one, as far as I know. It has drawbacks, but it does enforce you don’t use a
Unit
return type, doesn’t it?
a
type checking works as expected here
I don't agree, I'm not returning unit here
Copy code
val unit: Unit = something {
    1 
}
I'm returning an Int, so there's an implicit conversion from what I'm returning vs what I'm expecting (Unit), which should result in a compiler error instead of implicitly converting it
My suggestion was to trick the compiler
The problem here is that I cannot just duplicate or workaround every single function doing something similar just because now the compiler thinks this is fine, which wasn't before in previous Kotlin versions
w
Maybe you can find some hints as to why this changed in the changelog between the version that worked and the version that didn’t. I’m not sure your sample was failing in some Kotlin version, but implicit Unit return has been there for a long time afair
a
I remember having to adapt tests because they were expecting assertions (returning Unit) and sometimes a type was returned, causing an error 🤔 But yes, I'd love to know what changed, just not sure I have time to investigate that deep
t
You may also want to try running the compiler with builder Inference, if you’re on 1.6.0+
-Xenable-builder-inference
👀 1