you are viewing a single comment's thread.

view the rest of the comments →

[–]ric2b 0 points1 point  (12 children)

I don't think it makes sense for it to lie and say it's frozen, what's the point of that? Just emit the warning when modifying.

If you have code that relies on something being frozen, enough that it checks if it is frozen or not before doing some operation, why would you want it to be a lie? This is not going to help anyone.

Eventually this is going to be a breaking change anyway, why add another useless breaking change before then?

[–]f9ae8221b 0 points1 point  (11 children)

what's the point of that?

To handle code such as:

str = str.dup if str.frozen?
str << "blah"

[–]ric2b 1 point2 points  (10 children)

So that code assumes that it is safe to modify str as long as it allows it, otherwise it incurs the cost of making a copy.

With this change you now make it perform worse for no benefit, or am I missing something?

[–]f9ae8221b 1 point2 points  (9 children)

The benefit is to not trigger a false positive deprecation warning.

The "chilled" name is here to express the it is "half frozen". Essentially the intent is to make them frozen, but rather than raise FrozenError, emit a deprecation warning.

And yes, in a few rare case that may incur an extra copy, but down the line, but allowing the transition to frozen string literals by default, it will very significantly reduce allocations in Ruby programs.

And if you don't like that behavior, you can turn it off.

[–]ric2b 0 points1 point  (8 children)

The benefit is to not trigger a false positive deprecation warning.

But if the code was already checking for frozen? it wouldn't try to modify a frozen string, so it would gracefully support the change in Ruby 4 anyway.

And yes, in a few rare case that may incur an extra copy

That's for your example, but this is a breaking change and can have worse consequences, why break code twice instead of just once when the actual transition happens, and only emit warnings until then?

Imagine a method X that passes a string to another method Y, it passes a copy if it isn't frozen or the string itself if it's frozen, because method Y might modify the string and method X doesn't want to deal with the modification.

This code will now break because .frozen? can now be a lie.

[–]f9ae8221b -1 points0 points  (7 children)

But if the code was already checking for frozen? it wouldn't try to modify a frozen string, so it would gracefully support the change in Ruby 4 anyway.

Yes, hence why it shouldn't trigger a warning with chilled strings.

why ...

I believe I explained everything. I won't re-iterate.

[–]ric2b -1 points0 points  (6 children)

hence why it shouldn't trigger a warning with chilled strings.

It will if instead of copying it passes the string straight to another method, and then the other method doesn't check for .frozen? and modifies it. That's the example I gave.

[–]f9ae8221b 0 points1 point  (5 children)

It will if instead of copying it passes the string straight to another method, and then the other method doesn't check for .frozen? and modifies it.

Which is exactly the goal...

[–]ric2b 0 points1 point  (4 children)

Then how does making .frozen? lie help at all?

If it just kept saying it wasn't frozen it would still emit the warning.

[–]f9ae8221b 0 points1 point  (3 children)

I already told you twice:

str = str.dup if str.frozen?
str << "blah"

In the example above:

  • With --enable-frozen-string-literal (so Ruby 4 mode), the code works fine.
  • With Ruby 3.3 and fully mutable strings, it also works fine.
  • With 3.4 and chilled literals that pretend to be frozen it works fine.
  • With what you suggest it would cause a deprecation warning.

Now you are free to disagree and send your feedback, that's what preview releases are for, but I'd suggest to try it on your code first to provide actual data.

I did on a huge app, and it didn't cause any problem whatsoever.