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
Non adapting end of iteration on insert during iteration - difference between Ruby and JRuby #6371
Comments
Does not arise with
|
This issue is what currently makes CanCanCan tests fail on JRuby. |
While it's for sure weird that Ruby and JRuby behave differently, I'd ask myself what to expect when altering a collection I'm iterating over. Even more because your example mixes indexes and iterators. |
The issue also exists in iteration without index ^^
And I expect it to behave the same way that ruby does. I am well aware that other languages such as java permit such behaviour which is why I removed it from the codebase I found it in... but still... |
The official position of matz has always been that modification during iteration is an unspecified behavior, so I am not surprised to see a difference here. That said, we will make a best effort to match behavior here. |
The fix is fairly straightforward and follows similar changes in other iteration methods: diff --git a/core/src/main/java/org/jruby/RubyArray.java b/core/src/main/java/org/jruby/RubyArray.java
index 4b47dc522a..244ec9a07d 100644
--- a/core/src/main/java/org/jruby/RubyArray.java
+++ b/core/src/main/java/org/jruby/RubyArray.java
@@ -2828,7 +2828,7 @@ public class RubyArray<T extends IRubyObject> extends RubyObject implements List
int len0 = 0, len1 = 0;
try {
int i1, i2;
- for (i1 = i2 = 0; i1 < len; len0 = ++i1) {
+ for (i1 = i2 = 0; i1 < realLength; len0 = ++i1) {
final IRubyObject[] values = this.values;
// Do not coarsen the "safe" check, since it will misinterpret AIOOBE from the yield
// See JRUBY-5434 By memoizing the length, we don't provide any means for it to be updated during the loop, other than via our own deletions. This may be less safe for concurrency, since it will also see length changes by other threads and potentially try to walk off the end of the array. I will compare with CRuby to confirm this is how they handle the issue. |
Thank you for looking into it ^^ I agree that inserting into an array that is being iterated over is far from good practice. But it appears to be used in some cases and therefore I found it to be something I ought to report. |
This does appear to be how the equivalent code in CRuby is implemented. I will push this change to jruby-9.2 branch and it will be in 9.2.14 (if we do such a release) and 9.3. However I strongly discourage depending on this behavior, and it would be safest for you to eliminate such uses in your apps and libraries. This behavior is not tested by any of the existing compatibility suites – it's not in ruby/spec, not in CRuby's own tests, not in the additional tests JRuby has – because it is considered unspecified behavior. Behavior across Ruby implementations varies:
|
This is unspecified behavior, but because we try to match CRuby I am adding a test to our suite. See jruby#6371
This allows adding to the array while iterating. Previously, adding elements while iterating for delete_if would lose existing elements at the end, as they get pushed beyond our memoized size. This behavior is not specified, but we make a best effort to match CRuby behavior. There will be no specs added for this. Fixes #6371
This is unspecified behavior, but because we try to match CRuby I am adding a test to our suite. See #6371
Issue:
There seems to be a difference in how JRuby and Ruby handle insertion of elements into an array that is being iterated over.
The version of JRuby doesn't seem to matter. Therefore I suspect a fairly old incompatibility
Versions:
Test:
Running the test
Execute the code above with both JRuby and Ruby.
E.g. ruby file_name.rb
Expected Behavior
Ruby
Actual Behavior
JRuby
My guess
I guess that JRuby sets the max_index/end of an iteration at the beginning of an iteration and Ruby adapts that end if an insert occurs.
I do not want to impose this behaviour on JRuby if it is not how it's intended to be. But I expected it to behave like Ruby.
The text was updated successfully, but these errors were encountered: