SI-9691 BufferedIterator should expose an headOption#5277
SI-9691 BufferedIterator should expose an headOption#5277ChristopherDavenport wants to merge 4 commits intoscala:2.12.xfrom
Conversation
While I am uncertain if this is the appropriate context. With a simple if block this can be achieved and breaks no tests that I can see. The hasNext feature allows us to be aware whether or not we need to return the value wrapped or whether to return a None object which should allow this trait to proliferate. I was worried about where this coincided with already exists. However it appears that it was using override already where the mix occurs at. As it is implemented in the trait it should not affect current code.
|
Also I'd like to say I'm sorry if I failed to follow any standards or procedures either here or on the issues site. This is my first time attempting to contribute so I'm rather unsure of myself. |
|
Well my first attempt was naive, and I was missing an obvious test for whether or not this would perform at the end of an Iterator. I am working on a more complete approach currently. |
The hasNext method actually checks to see if the next value is nonEmpty, so rather than calling ahead in the sequence through a buffered itertaing we check if this exists, otherwise we generate the None. Test case now includes last value of an Iterator, the first, and an element past the end. The nonEmpty guarantees that head will no be called on a value unless it exists, buffering the call.
|
Well this turns out to do the exact same validation check as before however it appropriately works in the test cases as I didn't realize I was advancing the iterator past where I was evaluating. Hopefully this is seen as the best of both worlds as the implementation is left up to the inheritor. |
|
Hi, iterators are deceptively tricky. You're in good hands with @szeiger . You probably didn't intend this null handling: I don't know whether they'll want to add convenience API (which can be coded as extension methods). But I notice there's no way to ask a |
| if (this.nonEmpty) Option(head) | ||
| else None | ||
| } | ||
|
|
There was a problem hiding this comment.
IMHO, it looks better as a one-liner using hasNext. And Some(head).
|
I don't understand the argument for calling Agreed on the null handling. An @som-snytt I don't see how you could retrofit a method that checks whether the buffer is non-empty into |
|
I agree with you @szeiger . The options available don't really seem to make much sense. It belongs in GenTraversableLike, as it is. I tried hasNext realized a shortcoming at the end value of some Iterable implementations decided to use nonEmpty and did not realize that it was !hasNext until after I had posted the commit. The problem is as posted the iterator makes no guarantees as to the buffer, nor is it ever truly safe to do so. The buffered iterator is free to advance past the end of the stream. As it advances the Iterator and stores the value, however if no value exists we receive the error. We see this in the buffered function. It is doubly unnecessary as it can become a Transversable via the toStream method which would offer this functionality. Overall I am glad to have taken a shot at this, and learned a bit in the process but I am fairly certain that this not really the place. The buffer is unstable in both of the locations it is implemented. And traversable seems to make more sense, and it comforts me that my chosen implementation seems to mirrored it. Although I seem to have a lot more to learn about null in scala as my daily life in scala is so devoid of it. Thank you for your time and I will continue to try to help out. Was my overall approach acceptable? Anything I should do differently on another issue? |
|
What problems does |
This commit applies allows nulls to be inside the Some as appropriate for an Iterator and switches from the isEmpty method which is !hasNext to hasNext.
|
Well I believed incorrectly that I could implement a version where it would advance past the end of the list. Which is obviously untrue and a sign of my inexperience in this realm. I have added the test for null handling, and the code so that it uses hasNext. |
|
I think this implementation should be fine. The new method still needs a scaladoc comment. Testing Iterators is always tricky because of the (possibly intricate) mutable state. All your tests use a fresh |
|
Another consideration is binary compatibility. Unlike most projects in the Scala ecosystem which only guarantee backward compatibility between minor releases, Scala itself also guarantees forward compatibility. This means we cannot add new non-private methods in 2.12.x, so you need to target the 2.12.0 branch. |
The new tests demonstrate it works exactly on the bounds described and that the state is not mutated by the advancement, as suggested by buffered. Head and Head Option are interchangeable on a value that exists when head is wrapped with Some.
|
I have made the changes requested. I am uncertain what you mean about targeting for 2.12.0 vs 2.12.x, although I do understand the reason. Do I need to do something differently? |
| def head: A | ||
|
|
||
| /** Returns an option of the next element of an iterator without advancing beyond it. | ||
| * @return the next element of this iterator if it is has a next element |
There was a problem hiding this comment.
There's an "is" too many here. Same in the next line.
|
You can see the target branch at the top of this PR. You selected it when opening the PR (or not, because |
|
Oh, sorry, I just noticed that we haven't branched yet, so |
|
Closing for New Squashed Commit |
|
Just FYI, you don't need to create a new PR when you squash. Just do it in the original branch and |
While I am uncertain if this is the appropriate context. With a simple if block this can be achieved and breaks no tests that I can see. The hasNext feature allows us to be aware whether or not we need to return the value wrapped or whether to return a None object which should allow this trait to proliferate. I was worried about where this coincided with already exists. However it appears that it was using override already where the mix occurs at. As it is implemented in the trait it should not affect current code.
I am not sure if this is even an appropriate feature however I thought I could implement it so I wanted to try. Please let me know if anything needs to be done.