ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:94851] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
@ 2019-09-09  2:15 ` daniel
  2019-09-19  9:11 ` [ruby-core:94986] " duerst
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: daniel @ 2019-09-09  2:15 UTC (permalink / raw)
  To: ruby-core

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

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object is mutated can be far from where it was frozen.

I propose adding a flag which gives us a migration path for freezing objects. For purposes of discussion I will call this flag "eventually_frozen". It would change the behavior of the frozen flag so that mutating the object would result in a warning instead of an error. So code like `obj = obj.dup if obj.frozen?` and `+str` would work as expected. 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 could 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, 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(eventual:false)
   * if `eventual` is false
      * set frozen=true and eventually_frozen=false
   * if `eventual` is true
      * set frozen=true and eventually_frozen=true UNLESS frozen is already true
* String#-@
   * if eventually_frozen is true, deduplicate the string as if it was non-frozen
* Object#frozen?(eventual:true)
   * if `eventual` is false
      * return (frozen==true and eventually_frozen==false)
   * if `eventual` is true
      * return (frozen==true)
* rb_check_frozen
   * if eventually_frozen is true 
      * output warning
   * if eventually_frozen is false and frozen is true
      * raise error




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:94986] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
  2019-09-09  2:15 ` [ruby-core:94851] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings daniel
@ 2019-09-19  9:11 ` duerst
  2019-09-19 18:46 ` [ruby-core:94992] " daniel
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: duerst @ 2019-09-19  9:11 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by duerst (Martin Dürst).


`freeze(eventual: false)` gives the impression that it will never be frozen, but the proposal is to have this mean that it is frozen immediately.

So it would be better to say `freeze(immediately: true)` for what happens now, and `frozen(immediately: false)` for the new behavior.

Please also note the use of the `ly` ending, which makes it more grammatical English (but can be decided on independently).

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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(eventual:false)
   * if `eventual` keyword is false, set frozen=true and eventually_frozen=false
   * if `eventual` keyword is true, 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?(eventual:true)
   * return true if `eventual` keyword and eventually_frozen flag are both 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>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:94992] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
  2019-09-09  2:15 ` [ruby-core:94851] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings daniel
  2019-09-19  9:11 ` [ruby-core:94986] " duerst
@ 2019-09-19 18:46 ` daniel
  2019-09-20 11:32 ` [ruby-core:95003] " duerst
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: daniel @ 2019-09-19 18:46 UTC (permalink / raw)
  To: ruby-core

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

Description updated

The naming is a bit wonky, I'll freely admit. I'll change the description to your suggestion.

Does this mean you agree with the basic idea?

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95003] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2019-09-19 18:46 ` [ruby-core:94992] " daniel
@ 2019-09-20 11:32 ` duerst
  2019-09-21  8:33 ` [ruby-core:95016] " shevegen
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: duerst @ 2019-09-20 11:32 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by duerst (Martin Dürst).


Dan0042 (Daniel DeLorme) wrote:
> The naming is a bit wonky, I'll freely admit. I'll change the description to your suggestion.
> 
> Does this mean you agree with the basic idea?

The details and pros and cons were discussed at yesterday's Ruby committer meeting, with Matz present. I mostly commented on the naming, and I'm not sure I remember all the other details of the discussion correctly, sorry.

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95016] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2019-09-20 11:32 ` [ruby-core:95003] " duerst
@ 2019-09-21  8:33 ` shevegen
  2019-09-21 16:27 ` [ruby-core:95018] " mame
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: shevegen @ 2019-09-21  8:33 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by shevegen (Robert A. Heiler).


Hmm. I can somewhat understand the proposal, but I believe you would also
add a bit more complexity here; you need to remember that ruby users may
have to understand the idea behind this too, and that adds a bit of 
complexity. A bit like the Maybe monad in Haskell ... :P

Personally I think it would be much simpler to not introduce this, and to
instead have matz decide WHEN frozen strings will become the default (you
may  refer to all frozen objects but I think strings are the big ones, due
to them being used so much in ruby programs out there).

The main question or issue that matz mentioned was in regards to backwards
compatibility, e. g. for people to transition from ruby 2.x to ruby 3.0
without much problem, which is understandable in my opinion (see the
migration from ruby 1.8.x to ruby 2.0 which was not trivial for everyone).

On the other hand, I actually think it would be better to, rather than
add more complexity here, actually do the switch even if it may be
painful for people, just as headius proposed to then have frozen strings
by default for ruby 3.0. You can probably handle some of the problems
e. g. make some exception for old gems so that they work as-is or
something. I would prefer that much more compared to a maybe-frozen
situation; although I am also perfectly fine with frozen strings not
being the default in 3.0 either. At this point all my current and 
actively maintained code has a frozen-string comment so the change
would not affect my own code anyway; may be harder for cod that is
not maintained though.

I think the naming is not necessarily the biggest issue here; even
with a better name it may add complexity. Remember that in ruby
1.8 people did not have to think about it much at all since there
were no frozen strings; or at the least I can barely remember 
much code with "abc".freeze all over. That somehow was found in
later ruby code, where some people literally applied .freeze to
just about everything they could get their hands on. I always
found this sort of strange, too.

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95018] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2019-09-21  8:33 ` [ruby-core:95016] " shevegen
@ 2019-09-21 16:27 ` mame
  2019-09-23 20:43 ` [ruby-core:95046] " daniel
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: mame @ 2019-09-21 16:27 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by mame (Yusuke Endoh).


Matz didn't determine this proposal at the meeting.  There were four points discussed:

* Before matz accepts this proposal, he must decide the grand design change: Ruby should be immutable by default?
* If we want to make Ruby gradually immutable, this proposal is feasible.
* However, it is arguable if it is worthwhile consuming one bit for each object for this feature.
* Even after Ruby is immutable, it is doubtful if Ruby becomes so faster.

---

The following is my opinion.

I'm against making Ruby immutable by default.  One of the most important properties of Ruby is dynamics.  Ruby has allowed users to change almost anything in run time: dynamically (re)defining classes and methods (including core builtin ones), manipulating instance variables and local variables (via Binding) through encapsulation, etc.  These features are not recommended to abuse, but they actually bring big flexibility: monkey-patching, DRY, flexible operation, etc.  However, blindly freezing objects may spoil this usefulness.

It is a bit arguable if this flexibility limits performance.  Some people say that it is possible to make Ruby fast with the flexibility kept (TruffleRuby proves it).  That being said, I admit that the flexibility actually limits performance in the current MRI, and that we have no development resource to improve MRI so much in near future.  I think that my proposal #11934 was one possible way to balance the flexibility and performance.  Anyway, we need to estimate how much Ruby can be faster if the flexibility is dropped.  If it becomes 10 times faster, it is worth considering of course.  If it becomes 10 percent faster, it does not pay (in my opinion).

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95046] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2019-09-21 16:27 ` [ruby-core:95018] " mame
@ 2019-09-23 20:43 ` daniel
  2019-11-01 13:56 ` [ruby-core:95635] " daniel
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: daniel @ 2019-09-23 20:43 UTC (permalink / raw)
  To: ruby-core

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


I think it's important to make a distinction between "immutable" and "frozen".

Some programming languages have immutable data structures, and some programmers find that concept really cool, functional, powerful and whatnot. This is a "grand design" kind of thing. Like mame, I am very much **against** ruby going in that direction. It would only result in ruby becoming a half-assed functional language and no one would be happy.

On the other hand, freezing *certain* strings is merely an optimization concern. Not even all strings, just Symbol#to_s, Module#name and literals. Heck, just *static* string literals if I had anything to say about it. Certainly in many cases it's a premature optimization, but I still feel weirdly "uncomfortable" with all these extra strings objects being allocated when 99.9% of the time they're not needed.

In #16150 matz says "For frozen Symbol#to_s, I see a clear benefit. But I worry a little bit for incompatibility."
In #11473 he says "I REALLY like the idea but I am sure introducing this could cause HUGE compatibility issue"

This is not about some grand design to make ruby immutable, this is just about facilitating some specific desirable cases that are otherwise too hard because of incompatibility.

My proposal was to have the eventually_frozen flag visible and modifiable via regular ruby methods (because why not make it available to everyone?) But if there's a concern about overuse spoiling the flexibility and usefulness of ruby, I think it would also be fine to limit this to the C API and have the core team decide where is best to use it.


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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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




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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95635] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2019-09-23 20:43 ` [ruby-core:95046] " daniel
@ 2019-11-01 13:56 ` daniel
  2019-11-03 16:52 ` [ruby-core:95659] " eregontp
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: daniel @ 2019-11-01 13:56 UTC (permalink / raw)
  To: ruby-core

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

Description updated

Since returning a frozen string from Symbol#to_s [was reverted](https://bugs.ruby-lang.org/issues/16150#change-82420), it looks like this proposal is still relevant.

Is it realistic to wish for this in 2.7? The sooner the better imho.

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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, setting the eventually_frozen flag is not possible via ruby code. Object#freeze behaves as if `immediately=true`, and a C macro like `OBJ_EVENTUAL_FREEZE` is used in `rb_sym_to_s` and others to get the `immediately=false` behavior.



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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95659] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (7 preceding siblings ...)
  2019-11-01 13:56 ` [ruby-core:95635] " daniel
@ 2019-11-03 16:52 ` eregontp
  2019-11-03 16:58 ` [ruby-core:95660] " eregontp
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: eregontp @ 2019-11-03 16:52 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by Eregon (Benoit Daloze).


Dan0042 (Daniel DeLorme) wrote:
> Since returning a frozen string from Symbol#to_s [was reverted](https://bugs.ruby-lang.org/issues/16150#change-82420), it looks like this proposal is still relevant.

It's not reverted (yet at least).

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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, setting the eventually_frozen flag is not possible via ruby code. Object#freeze behaves as if `immediately=true`, and a C macro like `OBJ_EVENTUAL_FREEZE` is used in `rb_sym_to_s` and others to get the `immediately=false` behavior.



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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95660] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (8 preceding siblings ...)
  2019-11-03 16:52 ` [ruby-core:95659] " eregontp
@ 2019-11-03 16:58 ` eregontp
  2019-11-04 16:17 ` [ruby-core:95669] " daniel
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 13+ messages in thread
From: eregontp @ 2019-11-03 16:58 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by Eregon (Benoit Daloze).


For this discussion, I would focus on having this for Strings only initially.
I don't think it's about the "grand design of immutability", but rather a tool to ease migration towards frozen Strings for some APIs.

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.

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

* Author: Dan0042 (Daniel DeLorme)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
Freezing objects can give us a nice performance boost, but freezing previously non-frozen objects is a backward-incompatible change which is hard to handle because the place where the object 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 objects. 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, setting the eventually_frozen flag is not possible via ruby code. Object#freeze behaves as if `immediately=true`, and a C macro like `OBJ_EVENTUAL_FREEZE` is used in `rb_sym_to_s` and others to get the `immediately=false` behavior.



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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95669] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (9 preceding siblings ...)
  2019-11-03 16:58 ` [ruby-core:95660] " eregontp
@ 2019-11-04 16:17 ` daniel
  2019-11-06 10:49 ` [ruby-core:95721] " eregontp
  2019-11-06 11:09 ` [ruby-core:95723] " jean.boussier
  12 siblings, 0 replies; 13+ messages in thread
From: daniel @ 2019-11-04 16:17 UTC (permalink / raw)
  To: ruby-core

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/

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95721] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (10 preceding siblings ...)
  2019-11-04 16:17 ` [ruby-core:95669] " daniel
@ 2019-11-06 10:49 ` eregontp
  2019-11-06 11:09 ` [ruby-core:95723] " jean.boussier
  12 siblings, 0 replies; 13+ messages in thread
From: eregontp @ 2019-11-06 10:49 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by Eregon (Benoit Daloze).


Dan0042 (Daniel DeLorme) wrote:
> 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, it is useful for that pattern at least.
I think `String#+@` would be a better way to write that, but it's only available since Ruby 2.3.

I would also recommend an unconditional `.dup` to avoid mutating arguments, the fact a String is mutable doesn't mean there is no other reference to it which expects the String to not change.
That depends on the specific code around of course.

I think we all agree this is a good way to "deprecate" APIs returning mutable strings and let them return frozen strings in the future, isn't it?
This could be useful for instance for making `Symbol#to_s` return a frozen String after deprecation (#16150)

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

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [ruby-core:95723] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings
       [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
                   ` (11 preceding siblings ...)
  2019-11-06 10:49 ` [ruby-core:95721] " eregontp
@ 2019-11-06 11:09 ` jean.boussier
  12 siblings, 0 replies; 13+ messages in thread
From: jean.boussier @ 2019-11-06 11:09 UTC (permalink / raw)
  To: ruby-core

Issue #16153 has been updated by byroot (Jean Boussier).


> I think we all agree this is a good way to "deprecate" methods returning mutable strings and let them return frozen strings in the future, isn't it?
> This could be useful for instance for making `Symbol#to_s` return a frozen String after deprecation (#16150)

Agreed, not sure if we can still hope for the `Symbol#to_s` to make it to 2.7, but regardless having such way for marking strings (or other objects ?) as frozen in the next version would be convenient.


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

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-11-06 11:09 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-16153.20190909021526@ruby-lang.org>
2019-09-09  2:15 ` [ruby-core:94851] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings daniel
2019-09-19  9:11 ` [ruby-core:94986] " duerst
2019-09-19 18:46 ` [ruby-core:94992] " daniel
2019-09-20 11:32 ` [ruby-core:95003] " duerst
2019-09-21  8:33 ` [ruby-core:95016] " shevegen
2019-09-21 16:27 ` [ruby-core:95018] " mame
2019-09-23 20:43 ` [ruby-core:95046] " daniel
2019-11-01 13:56 ` [ruby-core:95635] " daniel
2019-11-03 16:52 ` [ruby-core:95659] " eregontp
2019-11-03 16:58 ` [ruby-core:95660] " eregontp
2019-11-04 16:17 ` [ruby-core:95669] " daniel
2019-11-06 10:49 ` [ruby-core:95721] " eregontp
2019-11-06 11:09 ` [ruby-core:95723] " jean.boussier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).