From: daniel@...42.com Date: 2019-09-23T20:43:15+00:00 Subject: [ruby-core:95046] [Ruby master Feature#16153] eventually_frozen flag to gradually phase-in frozen strings 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/ Unsubscribe: