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