<After discussing about Kotlin/Wasm experiments on...
# multiplatform
s
After discussing about Kotlin/Wasm experiments on WASI for server-side usage, I am digging a bit more on my spare time on Kotlin multiplatform support. I guess that's not something new or surprising, but the lack of standard library for typical desktop or server-side use cases like file IO is really a big drawback. I fully understand how it could be a pain to maintain for JetBrains team which has already a lot to do with Kotlin multiplatform support, but at the same time a proper multiplatform library for File, network, etc. would unlock IMO a lot of Kotlin Multiplatform potential, and allow much more code reuse and switch between platforms. And I think for Kotlin/Wasm WASI support where I am personnally interested, that will be needed at some point. On community side, for files I have seen https://square.github.io/okio/multiplatform/ or https://docs.korge.org/korio/. Is there other major ones? For network IO, I guess the most advanced incarnation looks like Ktor CIO. Is there any plan to make it available as a standalone library usable outside Ktor? Any middle-long term plans from JetBrains to standardize/maintain a multiplatform standard library with a wider scope? Or maybe any intent to provide an umbrella project or process to make it possible for the Kotlin community to contribute some bits with some kind of review / feedback from the Kotlin foundation members?
đź‘Ť 3
m
The Ktor roadmap has some partial answers:
Copy code
We're extracting the IO functionality into a separate library. This is a long-standing task that we've been working on gradually, and aim to finalize in 2023
I'd personally love Kotlin to endorse Okio as the default I/O library. It has kotlinx.serialization APIs already and some proven multiplatform usage. Using it everywhere would allow those Okio buffers to be shared without copy.
s
Interesting, thanks for sharing that.
o
Still, okio Buffer is always in-memory (list if segments with ByteArray under the hood) So it’s not the best fit for ktor, or other network things. F.e. sending files through tcp with current okio, will be not as efficient as possible (if we f.e. was able to use ButeBuffer/new MemorySegment apis for off heap access) So, API of okio is good choice for sync operations, but implementation is not so good for all use cases
s
0 copy multiplaform support for IO would be great, I am wondering if that's possible without advanced mechanism like compiler intrinsics.
o
ktor-io supports it - you can compose packet without copying and read it buffer by buffer (JVM buffer) But API isn’t so good for it and for now ktor-io API doesn’t play well for async API That’s why ktor team is working on new, better API I think, that for now we just need to wait for it And I don’t think, compiler support is needed here. The only thing that need to be carefully written is platform interop with those buffers (like, with java.nio), everything else should be easy, as with current okio API
j
Okio was initially built as the I/O component for OkHttp. Why do you consider it wouldn't work well for networking?
BufferedSource
->
NSInputStream
and
NSInputStream
->
Source
Apple Foundation 0 copy API support is implemented in this PR.
o
It works, but not optimal, no zero copy in some cases, f.e to send file through okio (or to transfer data from one socket to another) we will need to read(copy) data in memory (in chunks) from file/socket and then write(copy) it to file/socket. Because okio operates over ByteArrays we couldn’t do this without copying. F.e. read via FileChannel JVM APIs (operates over off heap ByteBuffers) and write it via SocketChannel (accepts both on and off heap ByteBuffers) Of course we couldn’t be sure, that there will be no copying somewhere in the middle, but still we can try our best Or take f.e. Netty which can work with both on heap and off heap buffers while maximising usage of off-heap buffers for IO, at least because they use JNI in transports and there only off-heap buffers can be used - all for maximum performance. Let’s take a look on what platform vs okio gives us: • JDK IO API provides access to both off-heap and on-heap - okio only on-heap • K/N provides CPointer<ByteVar> to access to any data and it could be not kotlin ByteArray but something outside of kotlin, produced even by different memory allocator or just some native library - okio only ByteArray ◦ regarding NS*Stream - not sure, about how Swift works with IO and is it possible via cinterop access data in zero-copy way, fAFAIK working with NSData now is only possible with fast copying (using memcpy) - but Im not an expert here at all. • on K/JS it looks ok to use ByteArray under the hood, but when we deep dive a little more, we can found, that there is SharedArrayBuffer. I would think, that with some type-erasure hacks we will be able to use it now, but who knows - okio only ByteArray • upcoming K/WASM (from what the topic was started), experimental unsafe linear memory access API introduced earlier shows, that even now at early stages ByteArray also not the only one possible representation of binary data - okio only ByteArray (in future) So, to conclude, okio is great library for working with buffers, but it’s not general IO library. That’s it, of course, it’s all just my thoughts and I could be wrong in some details 🙂
j
okio is great library for working with buffers, but it’s not general IO library.
Thanks for the detailed explanation. That makes sense. As for the
NSInputStream
API implementation, I was concerned extra memory copies would be necessary as well. But I found since it's possible to read and write directly to and from the
ByteArray
buffer as native
CPointer<uint8_tVar>
, it's possible to wrap the Okio API to implement the Apple Foundation API and vice versa, with only the single stream to buffer memory copy the APIs call for. It may be possible to accomplish something similar with JS and WASM APIs as well.