[#105544] [Ruby master Feature#18239] Variable Width Allocation: Strings — "peterzhu2118 (Peter Zhu)" <noreply@...>

Issue #18239 has been reported by peterzhu2118 (Peter Zhu).

18 messages 2021/10/04

[#105566] [Ruby master Bug#18242] Parser makes multiple assignment sad in confusing way — "danh337 (Dan Higgins)" <noreply@...>

Issue #18242 has been reported by danh337 (Dan Higgins).

9 messages 2021/10/06

[#105573] [Ruby master Bug#18243] Ractor.make_shareable does not freeze the receiver of a Proc but allows accessing ivars of it — "Eregon (Benoit Daloze)" <noreply@...>

Issue #18243 has been reported by Eregon (Benoit Daloze).

11 messages 2021/10/06

[#105618] [Ruby master Bug#18249] The ABI version of dev builds of CRuby does not correspond to the ABI — "Eregon (Benoit Daloze)" <noreply@...>

Issue #18249 has been reported by Eregon (Benoit Daloze).

23 messages 2021/10/11

[#105626] [Ruby master Bug#18250] Anonymous variables seem to break `Ractor.make_shareable` — "tenderlovemaking (Aaron Patterson)" <noreply@...>

Issue #18250 has been reported by tenderlovemaking (Aaron Patterson).

14 messages 2021/10/12

[#105660] [Ruby master Feature#18254] Add an `offset` parameter to String#unpack and String#unpack1 — "byroot (Jean Boussier)" <noreply@...>

Issue #18254 has been reported by byroot (Jean Boussier).

13 messages 2021/10/18

[#105672] [Ruby master Feature#18256] Change the canonical name of Thread::Mutex, Thread::Queue, Thread::SizedQueue and Thread::ConditionVariable to just Mutex, Queue, SizedQueue and ConditionVariable — "Eregon (Benoit Daloze)" <noreply@...>

Issue #18256 has been reported by Eregon (Benoit Daloze).

6 messages 2021/10/19

[#105692] [Ruby master Bug#18257] SystemTap/DTrace coredump on ppc64le/s390x — "vo.x (Vit Ondruch)" <noreply@...>

Issue #18257 has been reported by vo.x (Vit Ondruch).

22 messages 2021/10/20

[#105781] [Ruby master Misc#18266] DevelopersMeeting20211118Japan — "mame (Yusuke Endoh)" <noreply@...>

Issue #18266 has been reported by mame (Yusuke Endoh).

13 messages 2021/10/25

[#105805] [Ruby master Bug#18270] Refinement#{extend_object, append_features, prepend_features} should be removed — "shugo (Shugo Maeda)" <noreply@...>

Issue #18270 has been reported by shugo (Shugo Maeda).

8 messages 2021/10/26

[#105826] [Ruby master Feature#18273] Class.subclasses — "byroot (Jean Boussier)" <noreply@...>

Issue #18273 has been reported by byroot (Jean Boussier).

35 messages 2021/10/27

[#105833] [Ruby master Feature#18275] Add an option to define_method to not capture the surrounding environment — "vinistock (Vinicius Stock)" <noreply@...>

Issue #18275 has been reported by vinistock (Vinicius Stock).

11 messages 2021/10/27

[#105853] [Ruby master Feature#18276] `Proc#bind_call(obj)` same as `obj.instance_exec(..., &proc_obj)` — "ko1 (Koichi Sasada)" <noreply@...>

Issue #18276 has been reported by ko1 (Koichi Sasada).

15 messages 2021/10/28

[ruby-core:105709] [Ruby master Feature#18035] Introduce general model/semantic for immutable by default.

From: "ioquatix (Samuel Williams)" <noreply@...>
Date: 2021-10-21 03:21:42 UTC
List: ruby-core #105709
Issue #18035 has been updated by ioquatix (Samuel Williams).


After discussing it, we found some good ideas regarding immutability in Ruby.

Firstly, we need some definition for immutability. There appear to be two options.

(1) We can assume that `RB_FL_FREEZE | RB_FL_SHAREABLE` implies immutable objects. `RB_FL_FREEZE` implies the current object is frozen and `RB_FL_SHAREABLE` implies it was applied recursively (since only a completely frozen object-graph is considered shareable). The nice thing about this definition is that it works with existing objects that are frozen and shareable, including any sub-object within that.

(2) We can introduce a new flag, e.g. `RB_FL_IMMUTABLE` which implies immutable objects. `RB_FL_IMMUTABLE` would need to be applied and cached, and even if we introduced such a flag, unless care was taken, it would not be compatible with the frozen/shareable objects implicitly.

The biggest issue with (1) is that `rb_ractor_shareable_p` can update the `RB_FL_SHAREABLE` flag even though it presents the interface of being a predicate check (https://bugs.ruby-lang.org/issues/18258). We need to consider this carefully.

Regarding the interface changes, I see two important ones:

(1) Introduce `module Immutable` which is used by `class` to create immutable instances. Implementation is given already.

(2) Introduce `def Immutable(object)` which returns an immutable object (as yet not discussed).

Let's aim to implement (1) as discussed in this proposal, and we can discuss (2) later.

Regarding (1), there are only a few issues which need to be addressed, notably how `#dup` and `#clone` behave. For any immutable object, we need to be concerned about whether `#dup` and `#clone` can return mutable versions or not. We can check the current behaviour by assuming `Ractor.make_shareable(T_OBJECT)` returns immutable objects.

(1) Implementation of `#dup`. Traditional implementation returns mutable copy for normal object, and self for "immutable" objects. Overall, there are three possible implementations:

``` ruby
# (1)
immutable.dup()               # returns frozen, but not sharable (current)

# (2)
immutable.dup()               # raises an exception

# (3)
immutable.dup()               # returns self
```

Right now, we have some precedent (implemented in `object.c#special_object_p`), e.g.

``` ruby
5.dup # still immutable, return self.
:footer.dup # still immutable, return self.
```

Therefore, for immutable objects (3) makes the most sense (also most efficient option).

(2) Implementation of `#clone(freeze: true/false)`. It's similar to `#dup` but argument must be considered:

```
# (1)
immutable.clone()               # returns frozen, but not sharable (current)
immutable.clone(freeze: false) # returns unfrozen, not sharable (current)

# (2)
immutable.clone()               # returns frozen, and sharable
immutable.clone(freeze: false) # raises an exception

# (3)
immutable.clone()               # returns self
immutable.clone(freeze: false) # raises an exception
```

There is a precedent for this too:

```ruby
irb(main):001:0> :foo.clone(freeze: true)
=> :foo
irb(main):002:0> :foo.clone(freeze: false)
<internal:kernel>:48:in `clone': can't unfreeze Symbol (ArgumentError)
```

I believe (3) is the right approach because once a user object is frozen, un-freezing the top level is unlikely to create a working object, since all the internal state would still be frozen.

----------------------------------------
Feature #18035: Introduce general model/semantic for immutable by default.
https://bugs.ruby-lang.org/issues/18035#change-94207

* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
----------------------------------------
It would be good to establish some rules around mutability, immutability, frozen, and deep frozen in Ruby.

I see time and time again, incorrect assumptions about how this works in production code. Constants that aren't really constant, people using `#freeze` incorrectly, etc.

I don't have any particular preference but:

- We should establish consistent patterns where possible, e.g.
  - Objects created by `new` are mutable.
  - Objects created by literal are immutable.

We have problems with how `freeze` works on composite data types, e.g. `Hash#freeze` does not impact children keys/values, same for Array. Do we need to introduce `freeze(true)` or `#deep_freeze` or some other method?

Because of this, frozen does not necessarily correspond to immutable. This is an issue which causes real world problems.

I also propose to codify this where possible, in terms of "this class of object is immutable" should be enforced by the language/runtime, e.g.


```ruby
module Immutable
  def new(...)
    super.freeze
  end
end

class MyImmutableObject
  extend Immutable

  def initialize(x)
    @x = x
  end
  
  def freeze
    return self if frozen?
    
    @x.freeze
    
    super
  end
end

o = MyImmutableObject.new([1, 2, 3])
puts o.frozen?
```

Finally, this area has an impact to thread and fiber safe programming, so it is becoming more relevant and I believe that the current approach which is rather adhoc is insufficient.

I know that it's non-trivial to retrofit existing code, but maybe it can be done via magic comment, etc, which we already did for frozen string literals.



-- 
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>

In This Thread