-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make ByteString implement Iterable #294
Comments
On the JVM this would incur boxing and a ton of virtual dispatching making the performance pretty awful. What are you trying to do? |
Thanks for explaining. If I understand correctly, implementing I don't have one specific use case, but it seems all around practical because we immediately can use entire suites of extensions methods on I think the particular thing I noticed was that there is no existing I also feel convinced because since ByteString is immutable, it is particularly more safe to iterate than bytearray (even concurrently). On the topic of performance, I try to first write code that is safe, easy to read, and easy to maintain and try not to let performance preocupy me too much since in many real life scenarios these performance differences will be negligable. Also what's the point of computer hardware getting better if we don't let it shave off a few lines of code for us? If the consensus to implementing |
Every call to Kotlin does feature iterable specializations that avoid the boxing (
For actual collections of objects this makes sense. Unfortunately for bytes you are much better off treating them as large units. In the 10 years of Okio we have not needed to iterate a
The need to iterate bytes like this is not entirely uncommon, but if you're operating at the level of bytes you generally want to ingest with as little overhead as possible because you're interpreting those bytes as gzip data, png data, mp3 data, or something else. You aren't looking at each byte one-by-one and doing something with it individually.
This is a good strategy for high-level code which deals with objects and things. Correctness first, performance second. I'm not sure it makes sense at this layer of abstraction, however. Concrete use-cases of what you are trying to accomplish would go a long way in helping us understand if this is the right strategy or if there's a better one. Speculatively adding the feature, though, is unlikely to yield great results.
I'm not sure when you started using computers, but computers today are perceptively slower than older ones! Using programs on my 333Mhz PC twenty-five years ago was a much more responsive and snappy experience than my M3 Mac. The pace at which we've introduced indirection and abstraction at every layer has outpaced Moore's law (which itself has mostly died). The laws of thermodynamics and the speed of light remain fixed, and we're smack up against them now. The ability to process things efficiently, especially those represented in low-level constructs like a series of bytes, has actually become a competitive advantage for apps. |
Nice discussion!
They should, but for now it is a hidden knowledge for no reason. Filed https://youtrack.jetbrains.com/issue/KT-67379/ Example
This is quite a subtle topic, especially if/when we are going to move On the one hand, for passer-by usages (and if we are successful, we expect plenty of them!), the impedance mismatch would be quite noticeable -- why for On the other hand, at the very core, the API is quite specialized, and exposing inherently suboptimal operations is a questionable thing to do. Even if boxing is optimizeable via |
I share this sentiment: for apps, for tools, for IDEs, for everything, to be honest. This is the topic that puzzles me regularly -- from one perspective, we can only provide quite tailored APIs that are hard to misuse ([lack of] byte iteration is a nice example!); it might help, but comes with its own price. From the other perspective, being efficient cannot really be an afterthought for an app, and no amount of well-thought API can help it if it's not a consideration in the first place. All the convenience extensions will be written anyway if they are not here. The place on the spectrum from "efficient low-level API" and "convenient yet probably slower API" is really elusive, esp. for IO layer. |
Thank you both for the thoughtful answers! I have a lot to learn here.
Boxing is a topic I don't understand very well. Can someone point me to something I can read on this? Or is it something that can be explained here? I understand that the Iterator object will have to be instantiated, but I don't understand why the ByteString object will have to be repeatedly boxed and unboxed as opposed to boxed once and then have a reference of the box held by the iterator.
I see my request might be going against an important principle. That principle being that binary objects should be handled with bulk operations. I think I can respect this principle but still make a case for supporting iteration. One reason is debugging. If a bulk operation on a binary object has an issue, it might be useful to iterate one byte at a time and see what is going wrong, maybe with a breakpoint in there. Another reason is being able to maintain more of a flow state in your head when writing an operation on bytes in which you can immidiately think of how to do it byte-by-byte, but figuring out the appropriate bulk operation might take some more thought.
I started around 2005. I think this is a fascinating perspective but I personally don't see it. I mean, unless we are talking about gradle builds, that's about the only thing that is slow for me. But even there once the configuration cache was introduced it got super fast (at least when the configuration cache works correctly!). Then again, I take what you are saying as the truth given you have more experience.
For the record that's definitely what brought me here! It just stuck me as strange, even through I can see now there are valid reasons for the abscence of an iteration API on ByteString. This is indeed a nice topic. Maybe documenting the reasoning behind not including |
Iterator over Here's an example of an iterator over |
If you return a I forgot Kotlin has these iterator specializations. We of course never had access to them in Okio historially since it spent most of its life written in Java. That said, as soon as someone calls an extension on it like On Java all big-B |
Why does ByteString not implement Iterable? Was it a design decision, or was there just never a reason to?
It seems to me like it would be incredibly useful and 100% safe.
The text was updated successfully, but these errors were encountered: