Skip to content

[K/JS] Export Channel interface itself as well as SendChannel and Rec… - #4716

Open
JSMonk wants to merge 2 commits into
developfrom
export-channel-itself
Open

[K/JS] Export Channel interface itself as well as SendChannel and Rec…#4716
JSMonk wants to merge 2 commits into
developfrom
export-channel-itself

Conversation

@JSMonk

@JSMonk JSMonk commented Aug 4, 2026

Copy link
Copy Markdown
Member

…eiveChannel

^KT-80733

@dkhalanskyjb

Copy link
Copy Markdown
Collaborator

The purpose of this addition is unclear to me.

Channel is intended for the initial stage of establishing communication between several components—APIs should expose ReceiveChannel and SendChannel separately. In fact, in other concurrency libraries, instead of a unified Channel, it's common to return ReceiveChannel and SendChannel separately. So, the obvious use case of wanting the API boundaries between JS and Kotlin to be easily traversable doesn't seem relevant here.

You mention KT-80733 as the rationale, but that issue is dedicated to consuming a Flow—which only requires a ReceiveChannel. There's no mention of any use cases for Channel (or even SendChannel).

@JSMonk

JSMonk commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

The purpose of this addition is unclear to me.

Channel is intended for the initial stage of establishing communication between several components—APIs should expose ReceiveChannel and SendChannel separately. In fact, in other concurrency libraries, instead of a unified Channel, it's common to return ReceiveChannel and SendChannel separately. So, the obvious use case of wanting the API boundaries between JS and Kotlin to be easily traversable doesn't seem relevant here.

You mention KT-80733 as the rationale, but that issue is dedicated to consuming a Flow—which only requires a ReceiveChannel. There's no mention of any use cases for Channel (or even SendChannel).

I believe people would want to export channels like this:

@JsExport
class ViewModel {
   val channel = Channel<Data>() 
}

And this will not work (the compiler will trigger a warning that Channel is not an exportable type). So people would need to write like this in common code:

@JsExport
class ViewModel {
   @JsExport.Ignore
   val channel = Channel<Data>()
   
   @JsName("channel")
   val _channel: ReceiveChannel<Data> = channel
}

To not make their life complicated, I think it is worth marking itself as a Channel also exportable

@dkhalanskyjb

Copy link
Copy Markdown
Collaborator

I wouldn't expect them to write code like this in the first place. Exposing a Channel from the API leaves your users with too may functions to call, including both close and cancel, which are easy to mix up. As an API author, you want your callers to only have ReceiveChannel methods if they are supposed to be receiving, and only SendChannel methods if they're the senders. It's a mess otherwise.

There's a new language feature to help with this: https://kotlinlang.org/docs/whatsnew23.html#explicit-backing-fields With it, the second snippet becomes

class ViewModel {
   val channel: ReceiveChannel<Data>
       field = Channel<Data>()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants