From: ko1@...
Date: 2020-08-07T06:12:50+00:00
Subject: [ruby-core:99507] [Ruby master Feature#15504] Freeze all Range	object

Issue #15504 has been updated by ko1 (Koichi Sasada).


I got an issue on Ractor.

```ruby
def test
  (1..2)
end

r1 = test

Ractor.new do
  r2 = test
end.take
```

* compiler cached Range `(1..2)` because they begin and end are frozen literals. The test method returns the same range object.
* it means `test` returns not-immutable but same object. It violate the Ractor's memory model.

To solve it, there are two options.

(1) avoid cache at compile time.
(2) freeze Range objects which will be cached by th compiler.

For performance reason, I want to choose (2).

After that, could you please discuss all Range objects should be frozen or not.

Thanks,
Koichi

----------------------------------------
Feature #15504: Freeze all Range object
https://bugs.ruby-lang.org/issues/15504#change-86964

* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
# Abstrcat

Range is now non-frozen. How about to freeze all of Range objects?

# Background

We freeze some type of objects, Numerics (r47523) and Symbols [Feature #8906].
I believe making objects immutable solves some kind of programming difficulties.

`Range` is mutable, at least it is written in Range literal. So we can write the following weird program. 

```
2.times{
  r = (1..3)
  p r.instance_variable_get(:@foo)
  #=> 1st time: nil
  #=> 2nd time: :bar
  r.instance_variable_set(:@foo, :bar)
}
```

in `range.c`, there is a comment (thanks znz-san):

```
static void
range_modify(VALUE range)
{
    rb_check_frozen(range);
    /* Ranges are immutable, so that they should be initialized only once. */
    if (RANGE_EXCL(range) != Qnil) {
	rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
    }
}
```

# Patch

```
Index: range.c
===================================================================
--- range.c	(��������������� 66699)
+++ range.c	(���������������)
@@ -45,6 +45,8 @@
     RANGE_SET_EXCL(range, exclude_end);
     RANGE_SET_BEG(range, beg);
     RANGE_SET_END(range, end);
+
+    rb_obj_freeze(range);
 }
 
 VALUE
```

# Discussion

There are several usage of mutable Range in tests.

* (1) taint-flag
* (2) add singleton methods.
* (3) subclass with mutable states

Maybe (2) and (3) are points.

Thanks,
Koichi



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>