Issue #16153 has been updated by Dan0042 (Daniel DeLorme).

Description updated

Eregon (Benoit Daloze) wrote:
> For this discussion, I would focus on having this for Strings only initially.

Fair enough. I don't see much point in having this for objects other than strings. Focusing on strings might simplify the implementation.

> My main concern about it would be that such strings are reported as Kernel#frozen? but actually are not. That is some inconsistency.
> I think it would be more logical to return `false` for Kernel#frozen? and just have String#+@/String#dup make a copy without the eventually_frozen flag.

Let's keep in mind this is just a **temporary** bridge to reach frozen strings. As such I wouldn't worry too much about inconsistency. It's far more important that the bridge does a good job of facilitating migration. And for that I think it's necessary to handle the situation of `str = str.dup if str.frozen?` which is a pretty common pattern in ruby code. Right now I can't think of an example where returning false would be beneficial.

----------------------------------------
Feature #16153: eventually_frozen flag to gradually phase-in frozen strings
https://bugs.ruby-lang.org/issues/16153#change-82457

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing strings can give us a nice performance boost, but freezing previously non-frozen strings is a backward-incompatible change which is hard to handle because the place where the string is mutated can be far from where it was frozen, and tests might not cover the cases of frozen input vs non-frozen input.

I propose adding a flag which gives us a migration path for freezing strings. For purposes of discussion I will call this flag "eventually_frozen". It would act as a pseudo-frozen flag where mutating the object would result in a warning instead of an error. It would also change the return value of `Object#frozen?` so code like `obj = obj.dup if obj.frozen?` would work as expected to remove the warning. Note that eventually_frozen strings cannot be deduplicated, as they are in reality mutable.

This way it would be possible for Symbol#to_s (and many others) to return an eventually_frozen string in 2.7 which gives apps and gems time to migrate, before finally becoming a frozen deduplicated string in 3.0. This might even open up a migration path for eventually using `frozen_string_literal:true` as default. For example if it was possible to add `frozen_string_literal:eventual` to all files in a project (or as a global switch), we could run that in production to discover where to fix things, and then change it to `frozen_string_literal:true` for a bug-free performance boost.

### Proposed changes

* Object#freeze(immediately:true)
   * if `immediately` keyword is true, set frozen=true and eventually_frozen=false
   * if `immediately` keyword is false, set eventually_frozen=true UNLESS frozen flag is already true
* String#+@
   * if eventually_frozen is true, create a duplicate string with eventually_frozen=false
* Object#frozen?(immediately:false)
   * return true if `immediately` keyword is false and eventually_frozen flag is true
* rb_check_frozen
   * output warning if eventually_frozen flag is true

### Alternatively: the eventually_frozen flag is an internal detail only

* OBJ_EVENTUAL_FREEZE
   * used instead of OBJ_FREEZE in `rb_sym_to_s` and others to set eventually_frozen=true
* Object#freeze
   * set frozen=true and eventually_frozen=false
* String#+@
   * if eventually_frozen is true, create a duplicate string with eventually_frozen=false
* Object#frozen?
   * return true (or maybe `:eventually`) if eventually_frozen flag is true
* rb_check_frozen
   * output warning if eventually_frozen flag is true




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