# <!-- rdoc-file=set.c -->
# The Set class implements a collection of unordered values with no duplicates.
# It is a hybrid of Array's intuitive inter-operation facilities and Hash's fast
# lookup.
#
# Set is easy to use with Enumerable objects (implementing #each). Most of the
# initializer methods and binary operators accept generic Enumerable objects
# besides sets and arrays.  An Enumerable object can be converted to Set using
# the `to_set` method.
#
# Set uses a data structure similar to Hash for storage, except that it only has
# keys and no values.
#
# *   Equality of elements is determined according to Object#eql? and
#     Object#hash.  Use Set#compare_by_identity to make a set compare its
#     elements by their identity.
# *   Set assumes that the identity of each element does not change while it is
#     stored.  Modifying an element of a set will render the set to an
#     unreliable state.
# *   When a string is to be stored, a frozen copy of the string is stored
#     instead unless the original string is already frozen.
#
# ## Comparison
#
# The comparison operators `<`, `>`, `<=`, and `>=` are implemented as shorthand
# for the {proper_,}{subset?,superset?} methods.  The `<=>` operator reflects
# this order, or returns `nil` for sets that both have distinct elements (`{x,
# y}` vs. `{x, z}` for example).
#
# ## Example
#
#     s1 = Set[1, 2]                        #=> Set[1, 2]
#     s2 = [1, 2].to_set                    #=> Set[1, 2]
#     s1 == s2                              #=> true
#     s1.add("foo")                         #=> Set[1, 2, "foo"]
#     s1.merge([2, 6])                      #=> Set[1, 2, "foo", 6]
#     s1.subset?(s2)                        #=> false
#     s2.subset?(s1)                        #=> true
#
# ## Contact
#
# *   Akinori MUSHA <knu@iDaemons.org> (current maintainer)
#
# ## Inheriting from Set
#
# Before Ruby 4.0 (released December 2025), Set had a different, less efficient
# implementation. It was reimplemented in C, and the behavior of some of the
# core methods were adjusted.
#
# To keep backward compatibility, when a class is inherited from Set, additional
# module `Set::SubclassCompatible` is included, which makes the inherited class
# behavior, as well as internal method names, closer to what it was before Ruby
# 4.0.
#
# It can be easily seen, for example, in the #inspect method behavior:
#
#     p Set[1, 2, 3]
#     # prints "Set[1, 2, 3]"
#
#     class MySet < Set
#     end
#     p MySet[1, 2, 3]
#     # prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4
#
# For new code, if backward compatibility is not necessary, it is recommended to
# instead inherit from `Set::CoreSet`, which avoids including the
# "compatibility" layer:
#
#     class MyCoreSet < Set::CoreSet
#     end
#     p MyCoreSet[1, 2, 3]
#     # prints "MyCoreSet[1, 2, 3]"
#
# ## Set's methods
#
# First, what's elsewhere. Class Set:
#
# *   Inherits from [class Object](rdoc-ref:Object@What-27s+Here).
# *   Includes [module Enumerable](rdoc-ref:Enumerable@What-27s+Here), which
#     provides dozens of additional methods.
#
# In particular, class Set does not have many methods of its own for fetching or
# for iterating. Instead, it relies on those in Enumerable.
#
# Here, class Set provides methods that are useful for:
#
# *   [Creating a Set](rdoc-ref:Set@Methods+for+Creating+a+Set)
# *   [Set Operations](rdoc-ref:Set@Methods+for+Set+Operations)
# *   [Comparing](rdoc-ref:Set@Methods+for+Comparing)
# *   [Querying](rdoc-ref:Set@Methods+for+Querying)
# *   [Assigning](rdoc-ref:Set@Methods+for+Assigning)
# *   [Deleting](rdoc-ref:Set@Methods+for+Deleting)
# *   [Converting](rdoc-ref:Set@Methods+for+Converting)
# *   [Iterating](rdoc-ref:Set@Methods+for+Iterating)
# *   [And more....](rdoc-ref:Set@Other+Methods)
#
# ### Methods for Creating a Set
#
# *   ::[]: Returns a new set containing the given objects.
# *   ::new: Returns a new set containing either the given objects (if no block
#     given) or the return values from the called block (if a block given).
#
# ### Methods for Set Operations
#
# *   #| (aliased as #union and #+): Returns a new set containing all elements
#     from `self` and all elements from a given enumerable (no duplicates).
# *   #& (aliased as #intersection): Returns a new set containing all elements
#     common to `self` and a given enumerable.
# *   #- (aliased as #difference): Returns a copy of `self` with all elements in
#     a given enumerable removed.
# *   #^: Returns a new set containing all elements from `self` and a given
#     enumerable except those common to both.
#
# ### Methods for Comparing
#
# *   #<=>: Returns -1, 0, or 1 as `self` is less than, equal to, or greater
#     than a given object.
# *   #==: Returns whether `self` and a given enumerable are equal, as
#     determined by Object#eql?.
# *   #compare_by_identity?: Returns whether the set considers only identity
#     when comparing elements.
#
# ### Methods for Querying
#
# *   #length (aliased as #size): Returns the count of elements.
# *   #empty?: Returns whether the set has no elements.
# *   #include? (aliased as #member? and #===): Returns whether a given object
#     is an element in the set.
# *   #subset? (aliased as #<=): Returns whether a given object is a subset of
#     the set.
# *   #proper_subset? (aliased as #<): Returns whether a given enumerable is a
#     proper subset of the set.
# *   #superset? (aliased as #>=): Returns whether a given enumerable is a
#     superset of the set.
# *   #proper_superset? (aliased as #>): Returns whether a given enumerable is a
#     proper superset of the set.
# *   #disjoint?: Returns `true` if the set and a given enumerable have no
#     common elements, `false` otherwise.
# *   #intersect?: Returns `true` if the set and a given enumerable: have any
#     common elements, `false` otherwise.
# *   #compare_by_identity?: Returns whether the set considers only identity
#     when comparing elements.
#
# ### Methods for Assigning
#
# *   #add (aliased as #<<): Adds a given object to the set; returns `self`.
# *   #add?: If the given object is not an element in the set, adds it and
#     returns `self`; otherwise, returns `nil`.
# *   #merge: Merges the elements of each given enumerable object to the set;
#     returns `self`.
# *   #replace: Replaces the contents of the set with the contents of a given
#     enumerable.
#
# ### Methods for Deleting
#
# *   #clear: Removes all elements in the set; returns `self`.
# *   #delete: Removes a given object from the set; returns `self`.
# *   #delete?: If the given object is an element in the set, removes it and
#     returns `self`; otherwise, returns `nil`.
# *   #subtract: Removes each given object from the set; returns `self`.
# *   #delete_if - Removes elements specified by a given block.
# *   #select! (aliased as #filter!): Removes elements not specified by a given
#     block.
# *   #keep_if: Removes elements not specified by a given block.
# *   #reject! Removes elements specified by a given block.
#
# ### Methods for Converting
#
# *   #classify: Returns a hash that classifies the elements, as determined by
#     the given block.
# *   #collect! (aliased as #map!): Replaces each element with a block
#     return-value.
# *   #divide: Returns a hash that classifies the elements, as determined by the
#     given block; differs from #classify in that the block may accept either
#     one or two arguments.
# *   #flatten: Returns a new set that is a recursive flattening of `self`.
# *   #flatten!: Replaces each nested set in `self` with the elements from that
#     set.
# *   #inspect (aliased as #to_s): Returns a string displaying the elements.
# *   #join: Returns a string containing all elements, converted to strings as
#     needed, and joined by the given record separator.
# *   #to_a: Returns an array containing all set elements.
# *   #to_set: Returns `self` if given no arguments and no block; with a block
#     given, returns a new set consisting of block return values.
#
# ### Methods for Iterating
#
# *   #each: Calls the block with each successive element; returns `self`.
#
# ### Other Methods
#
# *   #reset: Resets the internal state; useful if an object has been modified
#     while an element in the set.
#
class Set[unchecked out A]
  include Enumerable[A]

  # <!--
  #   rdoc-file=set.c
  #   - Set.new -> new_set
  #   - Set.new(enum) -> new_set
  #   - Set.new(enum) { |elem| ... } -> new_set
  # -->
  # Creates a new set containing the elements of the given enumerable object.
  #
  # If a block is given, the elements of enum are preprocessed by the given block.
  #
  #     Set.new([1, 2])                       #=> Set[1, 2]
  #     Set.new([1, 2, 1])                    #=> Set[1, 2]
  #     Set.new([1, 'c', :s])                 #=> Set[1, "c", :s]
  #     Set.new(1..5)                         #=> Set[1, 2, 3, 4, 5]
  #     Set.new([1, 2, 3]) { |x| x * x }      #=> Set[1, 4, 9]
  #
  def initialize: (_Each[A]) -> untyped
                | [X] (_Each[X]) { (X) -> A } -> untyped
                | (?nil) -> untyped

  # <!--
  #   rdoc-file=set.c
  #   - Set[*objects] -> new_set
  # -->
  # Returns a new Set object populated with the given objects, See Set::new.
  #
  def self.[]: [X] (*X) -> Set[X]

  # <!--
  #   rdoc-file=set.c
  #   - set & enum -> new_set
  # -->
  # Returns a new set containing elements common to the set and the given
  # enumerable object.
  #
  #     Set[1, 3, 5] & Set[3, 2, 1]             #=> Set[3, 1]
  #     Set['a', 'b', 'z'] & ['a', 'b', 'c']    #=> Set["a", "b"]
  #
  def &: (_Each[A]) -> self

  # <!-- rdoc-file=set.c -->
  # Returns a new set containing elements common to the set and the given
  # enumerable object.
  #
  #     Set[1, 3, 5] & Set[3, 2, 1]             #=> Set[3, 1]
  #     Set['a', 'b', 'z'] & ['a', 'b', 'c']    #=> Set["a", "b"]
  #
  alias intersection &

  # <!--
  #   rdoc-file=set.c
  #   - set | enum -> new_set
  # -->
  # Returns a new set built by merging the set and the elements of the given
  # enumerable object.
  #
  #     Set[1, 2, 3] | Set[2, 4, 5]         #=> Set[1, 2, 3, 4, 5]
  #     Set[1, 5, 'z'] | (1..6)             #=> Set[1, 5, "z", 2, 3, 4, 6]
  #
  def |: (_Each[A]) -> self

  # <!-- rdoc-file=set.c -->
  # Returns a new set built by merging the set and the elements of the given
  # enumerable object.
  #
  #     Set[1, 2, 3] | Set[2, 4, 5]         #=> Set[1, 2, 3, 4, 5]
  #     Set[1, 5, 'z'] | (1..6)             #=> Set[1, 5, "z", 2, 3, 4, 6]
  #
  alias union |

  # <!-- rdoc-file=set.c -->
  # Returns a new set built by merging the set and the elements of the given
  # enumerable object.
  #
  #     Set[1, 2, 3] | Set[2, 4, 5]         #=> Set[1, 2, 3, 4, 5]
  #     Set[1, 5, 'z'] | (1..6)             #=> Set[1, 5, "z", 2, 3, 4, 6]
  #
  alias + |

  # <!--
  #   rdoc-file=set.c
  #   - set - enum -> new_set
  # -->
  # Returns a new set built by duplicating the set, removing every element that
  # appears in the given enumerable object.
  #
  #     Set[1, 3, 5] - Set[1, 5]                #=> Set[3]
  #     Set['a', 'b', 'z'] - ['a', 'c']         #=> Set["b", "z"]
  #
  def -: (_Each[A]) -> self

  # <!-- rdoc-file=set.c -->
  # Returns a new set built by duplicating the set, removing every element that
  # appears in the given enumerable object.
  #
  #     Set[1, 3, 5] - Set[1, 5]                #=> Set[3]
  #     Set['a', 'b', 'z'] - ['a', 'c']         #=> Set["b", "z"]
  #
  alias difference -

  # <!--
  #   rdoc-file=set.c
  #   - add(obj) -> self
  # -->
  # Adds the given object to the set and returns self.  Use `merge` to add many
  # elements at once.
  #
  #     Set[1, 2].add(3)                    #=> Set[1, 2, 3]
  #     Set[1, 2].add([3, 4])               #=> Set[1, 2, [3, 4]]
  #     Set[1, 2].add(2)                    #=> Set[1, 2]
  #
  def add: (A) -> self

  # <!-- rdoc-file=set.c -->
  # Adds the given object to the set and returns self.  Use `merge` to add many
  # elements at once.
  #
  #     Set[1, 2].add(3)                    #=> Set[1, 2, 3]
  #     Set[1, 2].add([3, 4])               #=> Set[1, 2, [3, 4]]
  #     Set[1, 2].add(2)                    #=> Set[1, 2]
  #
  alias << add

  # <!--
  #   rdoc-file=set.c
  #   - add?(obj) -> self or nil
  # -->
  # Adds the given object to the set and returns self. If the object is already in
  # the set, returns nil.
  #
  #     Set[1, 2].add?(3)                    #=> Set[1, 2, 3]
  #     Set[1, 2].add?([3, 4])               #=> Set[1, 2, [3, 4]]
  #     Set[1, 2].add?(2)                    #=> nil
  #
  def add?: (A) -> self?

  # <!--
  #   rdoc-file=set.c
  #   - include?(item) -> true or false
  # -->
  # Returns true if the set contains the given object:
  #
  #     Set[1, 2, 3].include? 2   #=> true
  #     Set[1, 2, 3].include? 4   #=> false
  #
  # Note that `include?` and `member?` do not test member equality using `==` as
  # do other Enumerables.
  #
  # This is aliased to #===, so it is usable in `case` expressions:
  #
  #     case :apple
  #     when Set[:potato, :carrot]
  #       "vegetable"
  #     when Set[:apple, :banana]
  #       "fruit"
  #     end
  #     # => "fruit"
  #
  # See also Enumerable#include?
  #
  def include?: (A) -> bool

  # <!-- rdoc-file=set.c -->
  # Returns true if the set contains the given object:
  #
  #     Set[1, 2, 3].include? 2   #=> true
  #     Set[1, 2, 3].include? 4   #=> false
  #
  # Note that `include?` and `member?` do not test member equality using `==` as
  # do other Enumerables.
  #
  # This is aliased to #===, so it is usable in `case` expressions:
  #
  #     case :apple
  #     when Set[:potato, :carrot]
  #       "vegetable"
  #     when Set[:apple, :banana]
  #       "fruit"
  #     end
  #     # => "fruit"
  #
  # See also Enumerable#include?
  #
  alias member? include?

  # <!--
  #   rdoc-file=set.c
  #   - set ^ enum -> new_set
  # -->
  # Returns a new set containing elements exclusive between the set and the given
  # enumerable object.  `(set ^ enum)` is equivalent to `((set | enum) - (set &
  # enum))`.
  #
  #     Set[1, 2] ^ Set[2, 3]                   #=> Set[3, 1]
  #     Set[1, 'b', 'c'] ^ ['b', 'd']           #=> Set["d", 1, "c"]
  #
  def ^: (_Each[A]) -> self

  # <!--
  #   rdoc-file=set.c
  #   - classify { |o| ... } -> hash
  #   - classify -> enumerator
  # -->
  # Classifies the set by the return value of the given block and returns a hash
  # of {value => set of elements} pairs.  The block is called once for each
  # element of the set, passing the element as parameter.
  #
  #     files = Set.new(Dir.glob("*.rb"))
  #     hash = files.classify { |f| File.mtime(f).year }
  #     hash       #=> {2000 => Set["a.rb", "b.rb"],
  #                #    2001 => Set["c.rb", "d.rb", "e.rb"],
  #                #    2002 => Set["f.rb"]}
  #
  # Returns an enumerator if no block is given.
  #
  def classify: [X] () { (A) -> X } -> Hash[X, self]

  # <!--
  #   rdoc-file=set.c
  #   - clear -> self
  # -->
  # Removes all elements and returns self.
  #
  #     set = Set[1, 'c', :s]             #=> Set[1, "c", :s]
  #     set.clear                         #=> Set[]
  #     set                               #=> Set[]
  #
  def clear: () -> self

  # <!--
  #   rdoc-file=set.c
  #   - collect! { |o| ... } -> self
  #   - collect! -> enumerator
  # -->
  # Replaces the elements with ones returned by `collect`. Returns an enumerator
  # if no block is given.
  #
  def collect!: () { (A) -> A } -> self

  # <!-- rdoc-file=set.c -->
  # Replaces the elements with ones returned by `collect`. Returns an enumerator
  # if no block is given.
  #
  alias map! collect!

  # <!--
  #   rdoc-file=set.c
  #   - delete(obj) -> self
  # -->
  # Deletes the given object from the set and returns self. Use subtract to delete
  # many items at once.
  #
  def delete: (A) -> self

  # <!--
  #   rdoc-file=set.c
  #   - delete?(obj) -> self or nil
  # -->
  # Deletes the given object from the set and returns self.  If the object is not
  # in the set, returns nil.
  #
  def delete?: (A) -> self?

  # <!--
  #   rdoc-file=set.c
  #   - delete_if { |o| ... } -> self
  #   - delete_if -> enumerator
  # -->
  # Deletes every element of the set for which block evaluates to true, and
  # returns self. Returns an enumerator if no block is given.
  #
  def delete_if: () { (A) -> untyped } -> self

  # <!--
  #   rdoc-file=set.c
  #   - reject! { |o| ... } -> self
  #   - reject! -> enumerator
  # -->
  # Equivalent to Set#delete_if, but returns nil if no changes were made. Returns
  # an enumerator if no block is given.
  #
  def reject!: () { (A) -> untyped } -> self?

  # <!--
  #   rdoc-file=set.c
  #   - compare_by_identity -> self
  # -->
  # Makes the set compare its elements by their identity and returns self.
  #
  def compare_by_identity: () -> self

  # <!--
  #   rdoc-file=set.c
  #   - compare_by_identity? -> true or false
  # -->
  # Returns true if the set will compare its elements by their identity.  Also see
  # Set#compare_by_identity.
  #
  def compare_by_identity?: () -> bool

  # <!--
  #   rdoc-file=set.c
  #   - disjoint?(set) -> true or false
  # -->
  # Returns true if the set and the given enumerable have no element in common.
  # This method is the opposite of `intersect?`.
  #
  #     Set[1, 2, 3].disjoint? Set[3, 4]   #=> false
  #     Set[1, 2, 3].disjoint? Set[4, 5]   #=> true
  #     Set[1, 2, 3].disjoint? [3, 4]      #=> false
  #     Set[1, 2, 3].disjoint? 4..5        #=> true
  #
  def disjoint?: (Set[A] | Enumerable[A]) -> bool

  # <!--
  #   rdoc-file=set.c
  #   - divide { |o1, o2| ... } -> set
  #   - divide { |o| ... } -> set
  #   - divide -> enumerator
  # -->
  # Divides the set into a set of subsets according to the commonality defined by
  # the given block.
  #
  # If the arity of the block is 2, elements o1 and o2 are in common if both
  # block.call(o1, o2) and block.call(o2, o1) are true. Otherwise, elements o1 and
  # o2 are in common if block.call(o1) == block.call(o2).
  #
  #     numbers = Set[1, 3, 4, 6, 9, 10, 11]
  #     set = numbers.divide { |i,j| (i - j).abs == 1 }
  #     set        #=> Set[Set[1],
  #                #       Set[3, 4],
  #                #       Set[6],
  #                #       Set[9, 10, 11]]
  #
  # Returns an enumerator if no block is given.
  #
  def divide: () { (A, A) -> Hash::_Key } -> Set[self]
            | () { (A) -> Hash::_Key } -> Set[self]

  # <!--
  #   rdoc-file=set.c
  #   - each { |o| ... } -> self
  #   - each -> enumerator
  # -->
  # Calls the given block once for each element in the set, passing the element as
  # parameter.  Returns an enumerator if no block is given.
  #
  def each: () { (A) -> void } -> self
          | () -> Enumerator[A, self]

  # <!--
  #   rdoc-file=set.c
  #   - empty? -> true or false
  # -->
  # Returns true if the set contains no elements.
  #
  def empty?: () -> bool

  # <!--
  #   rdoc-file=set.c
  #   - flatten -> set
  # -->
  # Returns a new set that is a copy of the set, flattening each containing set
  # recursively.
  #
  def flatten: () -> Set[untyped]

  # <!--
  #   rdoc-file=set.c
  #   - flatten! -> self
  # -->
  # Equivalent to Set#flatten, but replaces the receiver with the result in place.
  #  Returns nil if no modifications were made.
  #
  def flatten!: () -> self?

  # <!--
  #   rdoc-file=set.c
  #   - intersect?(set) -> true or false
  # -->
  # Returns true if the set and the given enumerable have at least one element in
  # common.
  #
  #     Set[1, 2, 3].intersect? Set[4, 5]   #=> false
  #     Set[1, 2, 3].intersect? Set[3, 4]   #=> true
  #     Set[1, 2, 3].intersect? 4..5        #=> false
  #     Set[1, 2, 3].intersect? [3, 4]      #=> true
  #
  def intersect?: (Set[A] | Enumerable[A]) -> bool

  # <!--
  #   rdoc-file=set.c
  #   - keep_if { |o| ... } -> self
  #   - keep_if -> enumerator
  # -->
  # Deletes every element of the set for which block evaluates to false, and
  # returns self. Returns an enumerator if no block is given.
  #
  def keep_if: () { (A) -> untyped } -> self

  # <!--
  #   rdoc-file=set.c
  #   - size -> integer
  # -->
  # Returns the number of elements.
  #
  def size: () -> Integer

  # <!-- rdoc-file=set.c -->
  # Returns the number of elements.
  #
  alias length size

  # <!--
  #   rdoc-file=set.c
  #   - merge(*enums, **nil) -> self
  # -->
  # Merges the elements of the given enumerable objects to the set and returns
  # self.
  #
  def merge: (*_Each[A]) -> self

  # <!--
  #   rdoc-file=set.c
  #   - subset?(set) -> true or false
  # -->
  # Returns true if the set is a subset of the given set.
  #
  def subset?: (self) -> bool

  # <!-- rdoc-file=set.c -->
  # Returns true if the set is a subset of the given set.
  #
  alias <= subset?

  # <!--
  #   rdoc-file=set.c
  #   - proper_subset?(set) -> true or false
  # -->
  # Returns true if the set is a proper subset of the given set.
  #
  def proper_subset?: (self) -> bool

  # <!-- rdoc-file=set.c -->
  # Returns true if the set is a proper subset of the given set.
  #
  alias < proper_subset?

  # <!--
  #   rdoc-file=set.c
  #   - superset?(set) -> true or false
  # -->
  # Returns true if the set is a superset of the given set.
  #
  def superset?: (self) -> bool

  # <!-- rdoc-file=set.c -->
  # Returns true if the set is a superset of the given set.
  #
  alias >= superset?

  # <!--
  #   rdoc-file=set.c
  #   - proper_superset?(set) -> true or false
  # -->
  # Returns true if the set is a proper superset of the given set.
  #
  def proper_superset?: (self) -> bool

  # <!-- rdoc-file=set.c -->
  # Returns true if the set is a proper superset of the given set.
  #
  alias > proper_superset?

  # <!--
  #   rdoc-file=set.c
  #   - replace(enum) -> self
  # -->
  # Replaces the contents of the set with the contents of the given enumerable
  # object and returns self.
  #
  #     set = Set[1, 'c', :s]             #=> Set[1, "c", :s]
  #     set.replace([1, 2])               #=> Set[1, 2]
  #     set                               #=> Set[1, 2]
  #
  def replace: (_Each[A]) -> self

  # <!--
  #   rdoc-file=set.c
  #   - reset -> self
  # -->
  # Resets the internal state after modification to existing elements and returns
  # self. Elements will be reindexed and deduplicated.
  #
  def reset: () -> self

  # <!--
  #   rdoc-file=set.c
  #   - select! { |o| ... } -> self
  #   - select! -> enumerator
  # -->
  # Equivalent to Set#keep_if, but returns nil if no changes were made. Returns an
  # enumerator if no block is given.
  #
  def select!: () { (A) -> untyped } -> self?

  # <!-- rdoc-file=set.c -->
  # Equivalent to Set#keep_if, but returns nil if no changes were made. Returns an
  # enumerator if no block is given.
  #
  alias filter! select!

  # <!--
  #   rdoc-file=set.c
  #   - subtract(enum) -> self
  # -->
  # Deletes every element that appears in the given enumerable object and returns
  # self.
  #
  def subtract: (_Each[A]) -> self

  # <!--
  #   rdoc-file=set.c
  #   - to_a -> array
  # -->
  # Returns an array containing all elements in the set.
  #
  #     Set[1, 2].to_a                    #=> [1, 2]
  #     Set[1, 'c', :s].to_a              #=> [1, "c", :s]
  #
  def to_a: () -> Array[A]

  # <!--
  #   rdoc-file=set.c
  #   - join(separator=nil)-> new_string
  # -->
  # Returns a string created by converting each element of the set to a string.
  #
  def join: (?string separator) -> String
end

%a{annotate:rdoc:skip}
module Enumerable[unchecked out Elem]
  # <!--
  #   rdoc-file=prelude.rb
  #   - to_set(*args, &block)
  # -->
  # Makes a set from the enumerable object with given arguments. Passing arguments
  # to this method is deprecated.
  #
  def to_set: () -> Set[Elem]
            | [T] () { (Elem) -> T } -> Set[T]
end
