-
Notifications
You must be signed in to change notification settings - Fork 191
Override freeze-related behaviour in RubyRange for compatibility with Ruby 3.0 #2570
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
Conversation
Is this to handle freeze state in |
1550895
to
dc37253
Compare
Extra context is that because This is preliminary work to fixing the frozen behaviour of Note that another conversation to have is that |
Ah, yes, not all Range are frozen, only instances of Range but not instances of subclasses of Ranges: https://bugs.ruby-lang.org/issues/15504#note-19 I think this is something to fix in CRuby at some point, it's a weird exception to immutable classes (https://gist.github.com/eregon/bce555fa9e9133ed27fbfc1deb181573). |
So we'd have |
No, in |
Benoit and I briefly chatted in the Graal Slack. I'm going to go ahead and update this PR with additional changes that bring in the |
Yeah, that could work. It'd still increase the footprint for all instances of these. I'm not sure which builtin classes are likely to be frozen (but not always frozen) and/or object_id, would be good to have some data on that. |
1f8f02d
to
4da431a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to fix the spec.
2f07b6d
to
94cfbac
Compare
@@ -223,7 +224,8 @@ protected RubyObjectRange dup(RubyObjectRange range) { | |||
getLanguage().objectRangeShape, | |||
range.excludedEnd, | |||
range.begin, | |||
range.end); | |||
range.end, | |||
range.frozen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.dup
should actually create an unfrozen copy:
irb(main):001:0> RUBY_VERSION
=> "3.0.2"
irb(main):002:0> (1..2).frozen?
=> true
irb(main):003:0> (1..2).dup.frozen?
=> false
Could you add specs for that (if there isn't already) and fix the behavior?
For the int and long ranges, we need to create non-frozen variants as well then (or create RubyObjectRange, but that seems not advantageous).
94cfbac
to
50115c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, thank you for the PR!
|
||
it "is not frozen if duplicated" do | ||
(42..).dup.should_not.frozen? | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should move to spec/ruby/core/range/dup_spec.rb, I'll do that.
I just remembered, there is a follow-up optimization related to this, range literals can be embedded in the AST:
However this is a problem for AST sharing (sharing the same AST for multiple execution contexts, which have different Ruby classes, etc), because RubyRange objects are currently not context-independent, they point to a given RubyClass ( @MattAlp Would you like to try that (separate PR of course) or you would prefer if somebody else works on that? It is a bit more involved than the change here but I think also not very difficult either. => moved to #2622 |
…bility with Ruby 3.0 (#2570) PullRequest: truffleruby/3120
Sure, I'll take it @eregon |
Update
As stated in the discussion below, this PR is now an optimization + compatibility change that modifies the behaviour of RubyRange and how it is used.
While working on #2453 and updating
Range
's behaviour to comply with 3.0, I discovered thatRubyRange
inherits fromRubyDynamicObject
, which exportsfreeze
andisFrozen
methods that dynamically set thefrozen?
property on the object.This proposed change implements the same pattern as seen in
RubyString
, which exposes afrozen
parameter in the constructor and overrides thefreeze
andisFrozen
methods to explicitly work on theboolean frozen
field. By doing so, the field is always present on the object and can default totrue
, rather than needing to be instantiated as a dynamic property. This also allows us to set the property at the appropriate call sites (i.e. tofalse
when creating an object in Ruby that inherits fromRange
).