https://kotlinlang.org logo
#compose
Title
# compose
e

eygraber

09/06/2021, 4:13 AM
If I have an interfacez:
Copy code
interface Renderer {
  fun render()
}

interface ComposeRenderer : Renderer {
   @Composable override fun render()
 }
will the compose mechanics work correctly if I call
render
polymorphically?
Copy code
class MyActivity : AppCompatActivity {
  private val renderer: Renderer = object : ComposableRenderer ...
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent { renderer.render() }
  }
}
a

Albert Chang

09/06/2021, 4:16 AM
As long as you also specify
@Composable
in your interface because
@Composable
changes the signature of the function.
e

eygraber

09/06/2021, 4:20 AM
In this case the value of `renderer`is inlined, so it's easy to see that it's an instance of
ComposableRenderer
. What about a case where the compiler can't deterministically see that it's a
ComposableRenderer
?
a

Albert Chang

09/06/2021, 4:23 AM
Composable functions are just standard functions with some extra parameters. They don't break the rules of Java/Kotlin including polymorphism.
e

eygraber

09/06/2021, 6:11 AM
Don't those extra parameters have to be added to the call site? How would the compiler know to add them?
a

Albert Chang

09/06/2021, 6:22 AM
The compiler plugin takes care of transforming the signatures of composable functions/lambdas and the invocation of them. I don't think there's much doc on these (as they are implementation details that may change from time to time) but if you are interested you can always read the source or check the byte code.
e

eygraber

09/06/2021, 7:00 AM
I was mostly asking rhetorically, as it's really just a restating of my question. When the compiler runs, it sees this as a call to
Renderer.render
which is not marked as composable. It has no idea that the actual Renderer implementation is
ComposableRenderer
, so I'd imagine that it wouldn't transform the signature. My question is then essentially, is there any way the compiler can infer that this actually is a composable call, and if not, I just want to confirm that the composable function wouldn't work.
a

Albert Chang

09/06/2021, 7:08 AM
That is exactly why it works only if you also specify 
@Composable
 in your interface.
h

hfhbd

09/06/2021, 8:44 AM
Copy code
interface ComposeRenderer : @Composable () -> Unit
In theory, this should work too, but I never tried it out.
e

eygraber

09/06/2021, 4:35 PM
The problem is I need
Renderer
and
ComposeRenderer
to stay as declared above.
z

Zach Klippenstein (he/him) [MOD]

09/07/2021, 2:15 PM
Does that even compile? I’d be surprised if it does, because composable functions have an entirely different signature than non-composable ones, so as far as the compiler is concerned that override isn't even valid. It’s like suspend functions: you can’t override a non-suspend function with a suspend function, or call a non-suspend function and expect it to suspend.
You can’t call a composable function from a non-composable function because the compiler needs to pass in some extra arguments and if the caller is not composable then it doesn’t know where to get those extra values.
3 Views