diff --git a/array.c b/array.c index db4c2c4802d..42aba64abed 100644 --- a/array.c +++ b/array.c @@ -637,17 +637,8 @@ ary_ensure_room_for_push(VALUE ary, long add_len) * call-seq: * freeze -> self * - * Freezes +self+ (if not already frozen); returns +self+: - * - * a = [] - * a.frozen? # => false - * a.freeze - * a.frozen? # => true - * - * No further changes may be made to +self+; - * raises FrozenError if a change is attempted. - * - * Related: Kernel#frozen?. + * Freezes +self+, preventing further modifications; + * see {Frozen Objects}[rdoc-ref:frozen_objects.md]. */ VALUE diff --git a/doc/language/frozen_objects.md b/doc/language/frozen_objects.md new file mode 100644 index 00000000000..394b0030b42 --- /dev/null +++ b/doc/language/frozen_objects.md @@ -0,0 +1,77 @@ +# Frozen Objects + +A Ruby object may be made immutable by freezing it with method `#freeze`, +which returns `self`; +method Kernel#frozen? returns whether an object is frozen: + +```ruby +a = %w[foo bar] # => ["foo", "bar"] +a.frozen? # => false +a << 'baz' # => ["foo", "bar", "baz"] +a.freeze # => ["foo", "bar", "baz"] +a.frozen? # => true +a << 'bat' # Raises FrozenError; can't modify frozen Array +``` + +A frozen object may not be unfrozen. + +In general, an object should be frozen if it should not be modified; +such objects may include: + +- Constants. +- Configuration objects. +- Lookup tables. +- Value objects. +- Objects shared across threads/Ractors. +- Strings in libraries. + +## Frozen Objects in Ruby + +Instances of these Ruby classes are always frozen: + +- `Symbol`. +- `Integer`. +- `Float`. +- `Rational`. +- `Complex`. +- `TrueClass`; has one instance: `true`. +- `FalseClass`; has one instance: `false`. +- `NilClass`; has one instance: `nil`. + +Other Ruby classes, including container classes (such as Array, Hash, and Set) +are by default not frozen. + +\String objects are by default not frozen, +but many Ruby libraries freeze their string objects, +commonly by placing a "magic comment" at the top of source files: + +```ruby +# frozen_string_literal: true +``` + +## Frozen User Objects + +Almost any object may be frozen: + +```ruby +KEYWORDS = %w[foo bar baz].freeze +# => ["foo", "bar", "baz"] +CONFIG = {foo: 0, bar: 1}.freeze +# => {foo: 0, bar: 1} +``` + +Freezing string objects enables deduplication, which can save memory and improve performance: + +```ruby +'foo'.object_id == 'foo'.object_id # => false # Two objects are stored. +'foo'.freeze.object_id == 'foo'.freeze.object_id # => true # Only one object is stored. +``` + +\String objects for an entire Ruby source file may be frozen via a "magic comment" +(which must be at the top of the file): + +```ruby +# frozen_string_literal: true + +'foo'.object_id == 'foo'.object_id # => true +``` diff --git a/kernel.rb b/kernel.rb index dc5cea1515d..2d1c2b0f91d 100644 --- a/kernel.rb +++ b/kernel.rb @@ -52,18 +52,8 @@ module Kernel # call-seq: # obj.frozen? -> true or false # - # Returns the freeze status of obj. - # - # a = [ "a", "b", "c" ] - # a.freeze #=> ["a", "b", "c"] - # a.frozen? #=> true - #-- - # Determines if the object is frozen. Equivalent to `Object#frozen?` in Ruby. - # @param[in] obj the object to be determines - # @retval Qtrue if frozen - # @retval Qfalse if not frozen - #++ - # + # Returns whether +self+ is frozen; + # see {Frozen Objects}[rdoc-ref:frozen_objects.md]. def frozen? Primitive.attr! :leaf Primitive.cexpr! 'rb_obj_frozen_p(self)' diff --git a/object.c b/object.c index 2e962b1c3ce..cbafd558f9f 100644 --- a/object.c +++ b/object.c @@ -1350,26 +1350,10 @@ rb_obj_dummy1(VALUE _x, VALUE _y) /* * call-seq: - * obj.freeze -> obj + * obj.freeze -> self * - * Prevents further modifications to obj. A - * FrozenError will be raised if modification is attempted. - * There is no way to unfreeze a frozen object. See also - * Object#frozen?. - * - * This method returns self. - * - * a = [ "a", "b", "c" ] - * a.freeze - * a << "z" - * - * produces: - * - * prog.rb:3:in `<<': can't modify frozen Array (FrozenError) - * from prog.rb:3 - * - * Objects of the following classes are always frozen: Integer, - * Float, Symbol. + * Freezes +self+, preventing further modifications; + * see {Frozen Objects}[rdoc-ref:frozen_objects.md]. */ VALUE diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 50cee40df44..d282936cc01 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -246,9 +246,11 @@ class Pathname raise e.class, "Pathname.new requires a String, #to_path or #to_str", cause: nil end + # call-seq: + # pathname.freeze -> self # - # Freze self. - # + # Freezes +self+, preventing further modifications; + # see {Frozen Objects}[rdoc-ref:frozen_objects.md]. def freeze super @path.freeze