https://kotlinlang.org logo
Title
m

mbonnin

12/07/2021, 2:31 PM
When a function takes a
Closeable
as a parameter, is there a nice way to indicate whether the function actually closes the
Closeable
or if it's the caller responsibility? Ideally looking at the signature only?
l

louiscad

12/07/2021, 2:59 PM
Name it
useXxx
if it closes it
m

mbonnin

12/07/2021, 2:59 PM
? gotcha
Makes sense 👍
l

louiscad

12/07/2021, 3:00 PM
One example is
useLines
m

mbonnin

12/07/2021, 3:00 PM
So I guess
Json.decodeFromStream(InputStream)
doesn't close the inputStream?
l

louiscad

12/07/2021, 3:01 PM
Good question
I'd think it does
Looks like a terminal operation to me.
m

mbonnin

12/07/2021, 3:02 PM
It does look like a terminal operation
But thinking a bit more about it, there are use cases where you have Json in the middle of an otherwise text document
l

louiscad

12/07/2021, 3:02 PM
InputStream is not just a Closeable
m

mbonnin

12/07/2021, 3:02 PM
In these cases, you don't want Json to close the document
l

louiscad

12/07/2021, 3:03 PM
True. Do you know if that function from kotlinx.serialization actually closes the stream?
m

mbonnin

12/07/2021, 3:03 PM
Looking quickly at the source, it doesn't seem so
Back to the initial point. Naming functions
useFoo()
isn't great either because it doesn't say anything about how it's going to "use" it
l

louiscad

12/07/2021, 3:04 PM
What if you call the function twice? Does it still work?
m

mbonnin

12/07/2021, 3:04 PM
Will try
l

louiscad

12/07/2021, 3:05 PM
Then just let folks wrap it with
use { … }
when it makes sense?
m

mbonnin

12/07/2021, 3:05 PM
Sure but if my function closes it, there's no need
l

louiscad

12/07/2021, 3:06 PM
If the use case is that no one should need to let it non-closed, makes sense to use
use
inside no matter the naming or the signature.
m

mbonnin

12/07/2021, 3:08 PM
The use cases is that given a generic
decode(InputStream)
function, I want to know if I should wrap in `use {}`or not. The current way seems to rely on the documentation or just "guess" like in the Json case
l

louiscad

12/07/2021, 3:12 PM
To me, it's more like "will I use the same instance more than once?"
m

mbonnin

12/07/2021, 3:15 PM
Yea but that's more or less the same thing, right? Can I continue using the same
inputStream
after the
decode
call or not
Unexpected JSON token at offset 68: Expected EOF after parsing, but had { instead
JSON input: kotlinx.serialization.json.internal.ArrayAsSequence@61a002b1
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 68: Expected EOF after parsing, but had { instead
JSON input: kotlinx.serialization.json.internal.ArrayAsSequence@61a002b1
Looks like
decodeFromStream
is doing yet something else 😅
It doesn't close but expects the end of file 🤔
l

louiscad

12/07/2021, 3:21 PM
Is there an overload that takes something different than an
InputStream
from
<http://java.io|java.io>
?
m

mbonnin

12/07/2021, 3:23 PM
Don't think so, the
InputStream
support is pretty new IIRC
l

louiscad

12/07/2021, 3:25 PM
Maybe you can make your own InputStream backed InputStream that emits a fake EOF when the boundary you want is reached?
m

mbonnin

12/07/2021, 3:25 PM
Mmmmm that sounds dangerous...
Also, that would emit the EOF after the Json object is finished parsing, which requires Json parsing
l

louiscad

12/07/2021, 3:26 PM
Isn't
InputStream
an interface?
m

mbonnin

12/07/2021, 3:26 PM
Sure but it means decoding Json twice
That's super bad
l

louiscad

12/07/2021, 3:27 PM
If it's json withing another document, like a markdown file, you can detect the closing ```
m

mbonnin

12/07/2021, 3:27 PM
Sure but I don't want to, I want kotlinx.serialization to do it for me 🙂
l

louiscad

12/07/2021, 3:28 PM
First time is just doing an indexOf/iteration, it's not json parsing in any way.
m

mbonnin

12/07/2021, 3:28 PM
I don't think there's a point in forcing the trailing EOF. I'll file a bug
l

louiscad

12/07/2021, 3:28 PM
Which is why kotlinx.serialization doesn't do it, it's not designed to detect when the input stops looking like JSON
m

mbonnin

12/07/2021, 3:28 PM
Stilli wasted CPU cycles
l

louiscad

12/07/2021, 3:29 PM
Not necessarily, the logic to find ``` is more more simple than JSON parsing itself
m

mbonnin

12/07/2021, 3:29 PM
Which is why you can't resume parsing the same inputStream
the logic to find ``` is more more simple than JSON parsing itself
It is but if you have to parse json in all cases, you don't want to waste cpu cycles searching for bacticks at the same time
l

louiscad

12/07/2021, 3:30 PM
Since an InputStream can come straight from network, I don't think you can always read the same instance twice.
m

mbonnin

12/07/2021, 3:30 PM
I'm not talking rewinding, I'm talking "continuing" reading the same stream
@Serializable
  class SimpleObject(val name: String)

  @Test
  fun testDecode() {
    val inputStream  = """
    {
      "name": "Object1"
    }
    {
      "name": "Object2"
    }
    """.trimIndent().byteInputStream()
    println("1")
    println(Json.decodeFromStream<SimpleObject>(inputStream).name)
    println("2")
    println(Json.decodeFromStream<SimpleObject>(inputStream).name)
  }
l

louiscad

12/07/2021, 3:31 PM
Iterating itself is not very expensive, it's the operations done during the iterations that can cost
m

mbonnin

12/07/2021, 3:32 PM
"not very expensive" is still > free
I want everything for free
😛
l

louiscad

12/07/2021, 3:32 PM
Then use C, and you will pay your calls to
free
m

mbonnin

12/07/2021, 3:33 PM
Yea, I'm ok paying for my garbage collector 😛
l

louiscad

12/07/2021, 3:33 PM
I'd measure the cost of iterating once to find the backticks and a second time for json parsing vs some code that manages both. Ensure you're using custom code for parsing to measure the same thing.
m

mbonnin

12/07/2021, 3:34 PM
I'll just file a bug 🙂
Because it's not only about cost, it's also about API design
l

louiscad

12/07/2021, 3:34 PM
To ask for EOF to be optional? That'd suit your needs fully?
m

mbonnin

12/07/2021, 3:35 PM
I want
decodeFromStream
to either: • parse a complete Json stream and close it • or allow parsing partial Json streams and leaving them open
The current behaviour has the drawbacks of both approaches
• Caller has to remember to wrap in
use {}
or else leaks happens • And at the same time it's not possible to decode partial streams
👍🏼 1
l

louiscad

12/07/2021, 3:37 PM
Waiting for the GitHub issue link like a hedgehog

https://c.tenor.com/ODCQZW2FncEAAAAM/sonic-hedgehog.gif

💙 1