Class: Erlang::Tuple

Inherits:
Object
  • Object
show all
Includes:
Associable, Enumerable
Defined in:
lib/erlang/tuple.rb

Overview

A Tuple is an ordered, integer-indexed collection of objects. Like Ruby's Array, Tuple indexing starts at zero and negative indexes count back from the end.

Tuple has a similar interface to Array. The main difference is methods that would destructively update an Array (such as #insert or #delete_at) instead return new Tuples and leave the existing one unchanged.

Creating New Tuples

Erlang::Tuple.new([:first, :second, :third])
Erlang::Tuple[1, 2, 3, 4, 5]

Retrieving Elements from Tuples

tuple = Erlang::Tuple[1, 2, 3, 4, 5]

tuple[0]      # => 1
tuple[-1]     # => 5
tuple[0,3]    # => Erlang::Tuple[1, 2, 3]
tuple[1..-1]  # => Erlang::Tuple[2, 3, 4, 5]
tuple.first   # => 1
tuple.last    # => 5

Creating Modified Tuples

tuple.add(6)            # => Erlang::Tuple[1, 2, 3, 4, 5, 6]
tuple.insert(1, :a, :b) # => Erlang::Tuple[1, :a, :b, 2, 3, 4, 5]
tuple.delete_at(2)      # => Erlang::Tuple[1, 2, 4, 5]
tuple + [6, 7]          # => Erlang::Tuple[1, 2, 3, 4, 5, 6, 7]

Licensing

Portions taken and modified from https://github.com/hamstergem/hamster

Copyright (c) 2009-2014 Simon Harris

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Associable

#dig

Methods included from Enumerable

#compact, #each_index, #grep, #grep_v, #group_by, #inspect, #join, #partition, #reject, #sum

Constructor Details

#initialize(elements = [].freeze) ⇒ Tuple

Returns a new instance of Tuple.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/erlang/tuple.rb', line 120

def initialize(elements=[].freeze)
  elements = elements.to_a.map { |element| Erlang.from(element) }
  if elements.size <= 32
    elements = elements.dup.freeze if !elements.frozen?
    @root, @size, @levels = elements, elements.size, 0
  else
    root, size, levels = elements, elements.size, 0
    while root.size > 32
      root = root.each_slice(32).to_a
      levels += 1
    end
    @root, @size, @levels = root.freeze, size, levels
  end
end

Instance Attribute Details

#sizeInteger (readonly) Also known as: arity, length

Return the number of elements in this Tuple

Returns:

  • (Integer)


75
76
77
# File 'lib/erlang/tuple.rb', line 75

def size
  @size
end

Class Method Details

.[](*elements) ⇒ Tuple

Create a new Tuple populated with the given elements.

Returns:



82
83
84
# File 'lib/erlang/tuple.rb', line 82

def [](*elements)
  return new(elements.freeze)
end

.compare(a, b) ⇒ Object

Raises:

  • (ArgumentError)


107
108
109
110
111
112
113
114
115
116
117
# File 'lib/erlang/tuple.rb', line 107

def compare(a, b)
  raise ArgumentError, "'a' must be of Erlang::Tuple type" if not a.kind_of?(Erlang::Tuple)
  raise ArgumentError, "'b' must be of Erlang::Tuple type" if not b.kind_of?(Erlang::Tuple)
  c = a.size <=> b.size
  i = 0
  while c == 0 and i < a.size and i < b.size
    c = Erlang.compare(a[i], b[i])
    i += 1
  end
  return c
end

.emptyTuple

Return an empty Tuple. If used on a subclass, returns an empty instance of that class.

Returns:



90
91
92
# File 'lib/erlang/tuple.rb', line 90

def empty
  return @empty ||= self.new
end

Instance Method Details

#*(times) ⇒ Tuple

Repetition. Return a new Tuple built by concatenating times copies of this one together.

Examples:

Erlang::Tuple["A", "B"] * 3
# => Erlang::Tuple["A", "B", "A", "B", "A", "B"]

Parameters:

  • times (Integer)

    The number of times to repeat the elements in this tuple

Returns:



806
807
808
809
810
811
# File 'lib/erlang/tuple.rb', line 806

def *(times)
  return self.class.empty if times == 0
  return self if times == 1
  result = (to_a * times)
  return result.is_a?(Array) ? self.class.new(result) : result
end

#+(other) ⇒ Tuple Also known as: concat

Return a new Tuple built by concatenating this one with other. other can be any object which is convertible to an Array using #to_a.

Examples:

Erlang::Tuple["A", "B", "C"] + ["D", "E"]
# => Erlang::Tuple["A", "B", "C", "D", "E"]

Parameters:

  • other (Enumerable)

    The collection to concatenate onto this tuple

Returns:



652
653
654
655
656
657
# File 'lib/erlang/tuple.rb', line 652

def +(other)
  other = Erlang.from(other)
  other = other.to_a
  other = other.dup if other.frozen?
  return replace_suffix(@size, other)
end

#add(element) ⇒ Tuple Also known as: <<, push

Return a new Tuple with element added after the last occupied position.

Examples:

Erlang::Tuple[1, 2].add(99)  # => Erlang::Tuple[1, 2, 99]

Parameters:

  • element (Object)

    The object to insert at the end of the tuple

Returns:



169
170
171
# File 'lib/erlang/tuple.rb', line 169

def add(element)
  return update_root(@size, Erlang.from(element))
end

#assoc(obj) ⇒ Object

Assumes all elements are nested, indexable collections, and searches through them, comparing obj with the first element of each nested collection. Return the first nested collection which matches, or nil if none is found. Behaviour is undefined when elements do not meet assumptions (i.e. are not indexable collections).

Examples:

t = Erlang::Tuple[Erlang::Tuple["A", 10], Erlang::Tuple["B", 20], Erlang::Tuple["C", 30]]
t.assoc("B")  # => Erlang::Tuple["B", 20]

Parameters:

  • obj (Object)

    The object to search for

Returns:

  • (Object)


1294
1295
1296
1297
1298
1299
1300
1301
# File 'lib/erlang/tuple.rb', line 1294

def assoc(obj)
  obj = Erlang.from(obj)
  each do |array|
    next if !array.respond_to?(:[])
    return array if obj == array[0]
  end
  return nil
end

#bsearch {|element| ... } ⇒ Object

Finds a value from this Tuple which meets the condition defined by the provided block, using a binary search. The tuple must already be sorted with respect to the block. See Ruby's Array#bsearch for details, behaviour is equivalent.

Examples:

t = Erlang::Tuple[1, 3, 5, 7, 9, 11, 13]
# Block returns true/false for exact element match:
t.bsearch { |e| e > 4 }      # => 5
# Block returns number to match an element in 4 <= e <= 7:
t.bsearch { |e| 1 - e / 4 }  # => 7

Yields:

  • Once for at most log n elements, where n is the size of the tuple. The exact elements and ordering are undefined.

Yield Parameters:

  • element (Object)

    element to be evaluated

Yield Returns:

  • (Boolean)

    true if this element matches the criteria, false otherwise.

  • (Integer)

    See Array#bsearch for details.

Returns:

  • (Object)

    The matched element, or nil if none found.

Raises:

  • TypeError if the block returns a non-numeric, non-boolean, non-nil value.



1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
# File 'lib/erlang/tuple.rb', line 1187

def bsearch
  return enum_for(:bsearch) if not block_given?
  low, high, result = 0, @size, nil
  while low < high
    mid = (low + ((high - low) >> 1))
    val = get(mid)
    v   = yield val
    if v.is_a? Numeric
      if v == 0
        return val
      elsif v > 0
        high = mid
      else
        low = mid + 1
      end
    elsif v == true
      result = val
      high = mid
    elsif !v
      low = mid + 1
    else
      raise TypeError, "wrong argument type #{v.class} (must be numeric, true, false, or nil)"
    end
  end
  return result
end

#clearTuple

Return an empty Tuple instance, of the same class as this one. Useful if you have multiple subclasses of Tuple and want to treat them polymorphically.

Returns:



1218
1219
1220
# File 'lib/erlang/tuple.rb', line 1218

def clear
  return self.class.empty
end

#combination(n) ⇒ self, Enumerator

When invoked with a block, yields all combinations of length n of elements from the Tuple, and then returns self. There is no guarantee about which order the combinations will be yielded.

If no block is given, an Enumerator is returned instead.

Examples:

t = Erlang::Tuple[5, 6, 7, 8]
t.combination(3) { |c| puts "Combination: #{c}" }

Combination: [5, 6, 7]
Combination: [5, 6, 8]
Combination: [5, 7, 8]
Combination: [6, 7, 8]
#=> Erlang::Tuple[5, 6, 7, 8]

Returns:

  • (self, Enumerator)


886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
# File 'lib/erlang/tuple.rb', line 886

def combination(n)
  return enum_for(:combination, n) if not block_given?
  return self if n < 0 || @size < n
  if n == 0
    yield []
  elsif n == 1
    each { |element| yield [element] }
  elsif n == @size
    yield self.to_a
  else
    combos = lambda do |result,index,remaining|
      while @size - index > remaining
        if remaining == 1
          yield result.dup << get(index)
        else
          combos[result.dup << get(index), index+1, remaining-1]
        end
        index += 1
      end
      index.upto(@size-1) { |i| result << get(i) }
      yield result
    end
    combos[[], 0, n]
  end
  return self
end

#delete(obj) ⇒ Tuple

Return a new Tuple with all elements which are equal to obj removed. #== is used for checking equality.

Examples:

Erlang::Tuple["C", "B", "A", "B"].delete("B")  # => Erlang::Tuple["C", "A"]

Parameters:

  • obj (Object)

    The object to remove (every occurrence)

Returns:



516
517
518
519
# File 'lib/erlang/tuple.rb', line 516

def delete(obj)
  obj = Erlang.from(obj)
  return select { |element| element != obj }
end

#delete_at(index) ⇒ Tuple

Return a new Tuple with the element at index removed. If the given index does not exist, return self.

Examples:

Erlang::Tuple["A", "B", "C", "D"].delete_at(2)
# => Erlang::Tuple["A", "B", "D"]

Parameters:

  • index (Integer)

    The index to remove

Returns:



412
413
414
415
416
417
418
# File 'lib/erlang/tuple.rb', line 412

def delete_at(index)
  return self if index >= @size || index < -@size
  index += @size if index < 0

  suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
  return replace_suffix(index, suffix.tap { |a| a.shift })
end

#drop(n) ⇒ Tuple

Drop the first n elements and return the rest in a new Tuple.

Examples:

Erlang::Tuple["A", "B", "C", "D", "E", "F"].drop(2)
# => Erlang::Tuple["C", "D", "E", "F"]

Parameters:

  • n (Integer)

    The number of elements to remove

Returns:

Raises:

  • ArgumentError if n is negative.



749
750
751
752
753
754
# File 'lib/erlang/tuple.rb', line 749

def drop(n)
  return self if n == 0
  return self.class.empty if n >= @size
  raise ArgumentError, "attempt to drop negative size" if n < 0
  return self.class.new(flatten_suffix(@root, @levels * BITS_PER_LEVEL, n, []))
end

#drop_whileTuple, Enumerator

Drop elements up to, but not including, the first element for which the block returns nil or false. Gather the remaining elements into a new Tuple. If no block is given, an Enumerator is returned instead.

Examples:

Erlang::Tuple[1, 3, 5, 7, 6, 4, 2].drop_while { |e| e < 5 }
# => Erlang::Tuple[5, 7, 6, 4, 2]

Returns:



778
779
780
781
# File 'lib/erlang/tuple.rb', line 778

def drop_while
  return enum_for(:drop_while) if not block_given?
  return self.class.new(super)
end

#each(&block) ⇒ self, Enumerator

Call the given block once for each element in the tuple, passing each element from first to last successively to the block. If no block is given, an Enumerator is returned instead.

Examples:

Erlang::Tuple["A", "B", "C"].each { |e| puts "Element: #{e}" }

Element: A
Element: B
Element: C
# => Erlang::Tuple["A", "B", "C"]

Returns:

  • (self, Enumerator)


469
470
471
472
473
# File 'lib/erlang/tuple.rb', line 469

def each(&block)
  return to_enum unless block_given?
  traverse_depth_first(@root, @levels, &block)
  return self
end

#empty?Boolean

Return true if this Tuple contains no elements.

Returns:

  • (Boolean)


138
139
140
# File 'lib/erlang/tuple.rb', line 138

def empty?
  return @size == 0
end

#eql?(other) ⇒ Boolean Also known as: ==

Return true if other has the same type and contents as this Tuple.

Parameters:

  • other (Object)

    The collection to compare with

Returns:

  • (Boolean)


1343
1344
1345
1346
1347
1348
1349
1350
1351
# File 'lib/erlang/tuple.rb', line 1343

def eql?(other)
  return true if other.equal?(self)
  if instance_of?(other.class)
    return false if @size != other.size
    return @root.eql?(other.instance_variable_get(:@root))
  else
    return !!(Erlang.compare(other, self) == 0)
  end
end

#erlang_inspect(raw = false) ⇒ String

Allows this Tuple to be printed using Erlang.inspect().

Returns:



1376
1377
1378
1379
1380
1381
# File 'lib/erlang/tuple.rb', line 1376

def erlang_inspect(raw = false)
  result = '{'
  each_with_index { |obj, i| result << ',' if i > 0; result << Erlang.inspect(obj, raw: raw) }
  result << '}'
  return result
end

#fetch(index) ⇒ Object #fetch(index) {|index| ... } ⇒ Object #fetch(index, default) ⇒ Object

Retrieve the value at index with optional default.

Overloads:

  • #fetch(index) ⇒ Object

    Retrieve the value at the given index, or raise an IndexError if not found.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D"]
    t.fetch(2)       # => "C"
    t.fetch(-1)      # => "D"
    t.fetch(4)       # => IndexError: index 4 outside of tuple bounds

    Parameters:

    • index (Integer)

      The index to look up

    Raises:

    • (IndexError)

      if index does not exist

  • #fetch(index) {|index| ... } ⇒ Object

    Retrieve the value at the given index, or return the result of yielding the block if not found.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D"]
    t.fetch(2) { |i| i * i }   # => "C"
    t.fetch(4) { |i| i * i }   # => 16

    Parameters:

    • index (Integer)

      The index to look up

    Yields:

    • Once if the index is not found.

    Yield Parameters:

    • index (Integer)

      The index which does not exist

    Yield Returns:

    • (Object)

      Default value to return

  • #fetch(index, default) ⇒ Object

    Retrieve the value at the given index, or return the provided default value if not found.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D"]
    t.fetch(2, "Z")  # => "C"
    t.fetch(4, "Z")  # => "Z"

    Parameters:

    • index (Integer)

      The index to look up

    • default (Object)

      Object to return if the key is not found

Returns:

  • (Object)


298
299
300
301
302
303
304
305
306
307
308
# File 'lib/erlang/tuple.rb', line 298

def fetch(index, default = (missing_default = true))
  if index >= -@size && index < @size
    return get(index)
  elsif block_given?
    return Erlang.from(yield(index))
  elsif !missing_default
    return Erlang.from(default)
  else
    raise IndexError, "index #{index} outside of tuple bounds"
  end
end

#fill(object) ⇒ Tuple #fill(object, index) ⇒ Tuple #fill(object, index, length) ⇒ Tuple

Replace a range of indexes with the given object.

Overloads:

  • #fill(object) ⇒ Tuple

    Return a new Tuple of the same size, with every index set to object.

    Examples:

    Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z")
    # => Erlang::Tuple["Z", "Z", "Z", "Z", "Z", "Z"]

    Parameters:

    • object (Object)

      Fill value.

  • #fill(object, index) ⇒ Tuple

    Return a new Tuple with all indexes from index to the end of the tuple set to object.

    Examples:

    Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z", 3)
    # => Erlang::Tuple["A", "B", "C", "Z", "Z", "Z"]

    Parameters:

    • object (Object)

      Fill value.

    • index (Integer)

      Starting index. May be negative.

  • #fill(object, index, length) ⇒ Tuple

    Return a new Tuple with length indexes, beginning from index, set to object. Expands the Tuple if length would extend beyond the current length.

    Examples:

    Erlang::Tuple["A", "B", "C", "D", "E", "F"].fill("Z", 3, 2)
    # => Erlang::Tuple["A", "B", "C", "Z", "Z", "F"]
    Erlang::Tuple["A", "B"].fill("Z", 1, 5)
    # => Erlang::Tuple["A", "Z", "Z", "Z", "Z", "Z"]

    Parameters:

    • object (Object)

      Fill value.

    • index (Integer)

      Starting index. May be negative.

    • length (Integer)

Returns:

Raises:

  • (IndexError)

    if index is out of negative range.



850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
# File 'lib/erlang/tuple.rb', line 850

def fill(object, index = 0, length = nil)
  raise IndexError if index < -@size
  object = Erlang.from(object)
  index += @size if index < 0
  length ||= @size - index # to the end of the array, if no length given

  if index < @size
    suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
    suffix.fill(object, 0, length)
  elsif index == @size
    suffix = Array.new(length, object)
  else
    suffix = Array.new(index - @size, nil).concat(Array.new(length, object))
    index = @size
  end

  return replace_suffix(index, suffix)
end

#firstObject

Return the first element in the Tuple. If the tuple is empty, return nil.

Examples:

Erlang::Tuple["A", "B", "C"].first  # => "A"

Returns:

  • (Object)


148
149
150
# File 'lib/erlang/tuple.rb', line 148

def first
  return get(0)
end

#flat_mapTuple

Return a new Tuple with the concatenated results of running the block once for every element in this Tuple.

Examples:

Erlang::Tuple[1, 2, 3].flat_map { |x| [x, -x] }
# => Erlang::Tuple[1, -1, 2, -2, 3, -3]

Returns:



544
545
546
547
548
# File 'lib/erlang/tuple.rb', line 544

def flat_map
  return enum_for(:flat_map) if not block_given?
  return self if empty?
  return self.class.new(super)
end

#flatten(level = -1)) ⇒ Tuple

Return a new Tuple with all nested tuples and arrays recursively "flattened out". That is, their elements inserted into the new Tuple in the place where the nested array/tuple originally was. If an optional level argument is provided, the flattening will only be done recursively that number of times. A level of 0 means not to flatten at all, 1 means to only flatten nested arrays/tuples which are directly contained within this Tuple.

Examples:

t = Erlang::Tuple["A", Erlang::Tuple["B", "C", Erlang::Tuple["D"]]]
t.flatten(1)
# => Erlang::Tuple["A", "B", "C", Erlang::Tuple["D"]]
t.flatten
# => Erlang::Tuple["A", "B", "C", "D"]

Parameters:

  • level (Integer) (defaults to: -1))

    The depth to which flattening should be applied

Returns:



631
632
633
634
635
636
637
638
639
640
641
# File 'lib/erlang/tuple.rb', line 631

def flatten(level = -1)
  return self if level == 0
  array = self.to_a
  if array.frozen?
    return self.class.new(array.flatten(level).freeze)
  elsif array.flatten!(level) # returns nil if no changes were made
    return self.class.new(array.freeze)
  else
    return self
  end
end

#get(index) ⇒ Object Also known as: at

Retrieve the element at index. If there is none (either the provided index is too high or too low), return nil.

Examples:

t = Erlang::Tuple["A", "B", "C", "D"]
t.get(2)   # => "C"
t.get(-1)  # => "D"
t.get(4)   # => nil

Parameters:

  • index (Integer)

    The index to retrieve

Returns:

  • (Object)


251
252
253
254
255
256
# File 'lib/erlang/tuple.rb', line 251

def get(index)
  return nil if @size == 0
  index += @size if index < 0
  return nil if index >= @size || index < 0
  return leaf_node_for(@root, @levels * BITS_PER_LEVEL, index)[index & INDEX_MASK]
end

#hashInteger

See Object#hash.

Returns:

  • (Integer)


1356
1357
1358
# File 'lib/erlang/tuple.rb', line 1356

def hash
  return reduce(Erlang::Tuple.hash) { |hash, item| (hash << 5) - hash + item.hash }
end

#insert(index, *elements) ⇒ Tuple

Return a new Tuple with the given values inserted before the element at index. If index is greater than the current length, nil values are added to pad the Tuple to the required size.

Examples:

Erlang::Tuple["A", "B", "C", "D"].insert(2, "X", "Y", "Z")
# => Erlang::Tuple["A", "B", "X", "Y", "Z", "C", "D"]
Erlang::Tuple[].insert(2, "X", "Y", "Z")
# => Erlang::Tuple[nil, nil, "X", "Y", "Z"]

Parameters:

  • index (Integer)

    The index where the new elements should go

  • elements (Array)

    The elements to add

Returns:

Raises:

  • (IndexError)

    if index exceeds negative range.



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/erlang/tuple.rb', line 384

def insert(index, *elements)
  raise IndexError if index < -@size
  index += @size if index < 0

  elements = elements.map { |element| Erlang.from(element) }

  if index < @size
    suffix = flatten_suffix(@root, @levels * BITS_PER_LEVEL, index, [])
    suffix.unshift(*elements)
  elsif index == @size
    suffix = elements
  else
    suffix = Array.new(index - @size, nil).concat(elements)
    index = @size
  end

  return replace_suffix(index, suffix)
end

#lastObject

Return the last element in the Tuple. If the tuple is empty, return nil.

Examples:

Erlang::Tuple["A", "B", "C"].last  # => "C"

Returns:

  • (Object)


158
159
160
# File 'lib/erlang/tuple.rb', line 158

def last
  return get(-1)
end

#mapTuple, Enumerator Also known as: collect

Invoke the given block once for each element in the tuple, and return a new Tuple containing the values returned by the block. If no block is provided, return an enumerator.

Examples:

Erlang::Tuple[3, 2, 1].map { |e| e * e }  # => Erlang::Tuple[9, 4, 1]

Returns:



529
530
531
532
533
# File 'lib/erlang/tuple.rb', line 529

def map
  return enum_for(:map) if not block_given?
  return self if empty?
  return self.class.new(super)
end

#permutation(n = @size) ⇒ self, Enumerator

Yields all permutations of length n of elements from the Tuple, and then returns self. If no length n is specified, permutations of all elements will be yielded.

There is no guarantee about which order the permutations will be yielded in.

If no block is given, an Enumerator is returned instead.

Examples:

t = Erlang::Tuple[5, 6, 7]
t.permutation(2) { |p| puts "Permutation: #{p}" }

Permutation: [5, 6]
Permutation: [5, 7]
Permutation: [6, 5]
Permutation: [6, 7]
Permutation: [7, 5]
Permutation: [7, 6]
# => Erlang::Tuple[5, 6, 7]

Returns:

  • (self, Enumerator)


989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
# File 'lib/erlang/tuple.rb', line 989

def permutation(n = @size)
  return enum_for(:permutation, n) if not block_given?
  if n < 0 || @size < n
    # yield nothing
  elsif n == 0
    yield []
  elsif n == 1
    each { |element| yield [element] }
  else
    used, result = [], []
    perms = lambda do |index|
      0.upto(@size-1) do |i|
        if !used[i]
          result[index] = get(i)
          if index < n-1
            used[i] = true
            perms[index+1]
            used[i] = false
          else
            yield result.dup
          end
        end
      end
    end
    perms[0]
  end
  return self
end

#popTuple

Return a new Tuple with the last element removed. Return self if empty.

Examples:

Erlang::Tuple["A", "B", "C"].pop  # => Erlang::Tuple["A", "B"]

Returns:



427
428
429
430
# File 'lib/erlang/tuple.rb', line 427

def pop
  return self if @size == 0
  return replace_suffix(@size-1, [])
end

#product(*tuples) ⇒ Tuple #productTuple

Cartesian product or multiplication.

Overloads:

  • #product(*tuples) ⇒ Tuple

    Return a Tuple of all combinations of elements from this Tuple and each of the given tuples or arrays. The length of the returned Tuple is the product of self.size and the size of each argument tuple or array.

    Examples:

    t1 = Erlang::Tuple[1, 2, 3]
    t2 = Erlang::Tuple["A", "B"]
    t1.product(t2)
    # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"], [3, "B"]]
  • #productTuple

    Return the result of multiplying all the elements in this Tuple together.

    Examples:

    Erlang::Tuple[1, 2, 3, 4, 5].product  # => 120

Returns:



1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
# File 'lib/erlang/tuple.rb', line 1087

def product(*tuples)
  tuples = tuples.map { |tuple| Erlang.from(tuple) }
  # if no tuples passed, return "product" as in result of multiplying all elements
  return super if tuples.empty?

  tuples.unshift(self)

  if tuples.any?(&:empty?)
    return block_given? ? self : []
  end

  counters = Array.new(tuples.size, 0)

  bump_counters = lambda do
    i = tuples.size-1
    counters[i] += 1
    while counters[i] == tuples[i].size
      counters[i] = 0
      i -= 1
      return true if i == -1 # we are done
      counters[i] += 1
    end
    false # not done yet
  end
  build_array = lambda do
    array = []
    counters.each_with_index { |index,i| array << tuples[i][index] }
    array
  end

  if block_given?
    while true
      yield build_array[]
      return self if bump_counters[]
    end
  else
    result = []
    while true
      result << build_array[]
      return result if bump_counters[]
    end
  end
end

#put(index, element) ⇒ Tuple #put(index) {|existing| ... } ⇒ Tuple Also known as: set

Return a new Tuple with a new value at the given index. If index is greater than the length of the tuple, the returned tuple will be padded with nils to the correct size.

Overloads:

  • #put(index, element) ⇒ Tuple

    Return a new Tuple with the element at index replaced by element.

    Examples:

    Erlang::Tuple[1, 2, 3, 4].put(2, 99)
    # => Erlang::Tuple[1, 2, 99, 4]
    Erlang::Tuple[1, 2, 3, 4].put(-1, 99)
    # => Erlang::Tuple[1, 2, 3, 99]
    Erlang::Tuple[].put(2, 99)
    # => Erlang::Tuple[nil, nil, 99]

    Parameters:

    • element (Object)

      The object to insert into that position

  • #put(index) {|existing| ... } ⇒ Tuple

    Return a new Tuple with the element at index replaced by the return value of the block.

    Examples:

    Erlang::Tuple[1, 2, 3, 4].put(2) { |v| v * 10 }
    # => Erlang::Tuple[1, 2, 30, 4]

    Yields:

    • (existing)

      Once with the existing value at the given index.

Parameters:

  • index (Integer)

    The index to update. May be negative.

Returns:

Raises:

  • (IndexError)


202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/erlang/tuple.rb', line 202

def put(index, element = yield(get(index)))
  raise IndexError, "index #{index} outside of tuple bounds" if index < -@size
  element = Erlang.from(element)
  index += @size if index < 0
  if index > @size
    suffix = Array.new(index - @size, nil)
    suffix << element
    return replace_suffix(@size, suffix)
  else
    return update_root(index, element)
  end
end

#rassoc(obj) ⇒ Object

Assumes all elements are nested, indexable collections, and searches through them, comparing obj with the second element of each nested collection. Return the first nested collection which matches, or nil if none is found. Behaviour is undefined when elements do not meet assumptions (i.e. are not indexable collections).

Examples:

t = Erlang::Tuple[Erlang::Tuple["A", 10], Erlang::Tuple["B", 20], Erlang::Tuple["C", 30]]
t.rassoc(20)  # => Erlang::Tuple["B", 20]

Parameters:

  • obj (Object)

    The object to search for

Returns:

  • (Object)


1315
1316
1317
1318
1319
1320
1321
1322
# File 'lib/erlang/tuple.rb', line 1315

def rassoc(obj)
  obj = Erlang.from(obj)
  each do |array|
    next if !array.respond_to?(:[])
    return array if obj == array[1]
  end
  return nil
end

#repeated_combination(n) ⇒ self, Enumerator

When invoked with a block, yields all repeated combinations of length n of tuples from the Tuple, and then returns self. A "repeated combination" is one in which any tuple from the Tuple can appear consecutively any number of times.

There is no guarantee about which order the combinations will be yielded in.

If no block is given, an Enumerator is returned instead.

Examples:

t = Erlang::Tuple[5, 6, 7, 8]
t.repeated_combination(2) { |c| puts "Combination: #{c}" }

Combination: [5, 5]
Combination: [5, 6]
Combination: [5, 7]
Combination: [5, 8]
Combination: [6, 6]
Combination: [6, 7]
Combination: [6, 8]
Combination: [7, 7]
Combination: [7, 8]
Combination: [8, 8]
# => Erlang::Tuple[5, 6, 7, 8]

Returns:

  • (self, Enumerator)


939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
# File 'lib/erlang/tuple.rb', line 939

def repeated_combination(n)
  return enum_for(:repeated_combination, n) if not block_given?
  if n < 0
    # yield nothing
  elsif n == 0
    yield []
  elsif n == 1
    each { |element| yield [element] }
  elsif @size == 0
    # yield nothing
  else
    combos = lambda do |result,index,remaining|
      while index < @size-1
        if remaining == 1
          yield result.dup << get(index)
        else
          combos[result.dup << get(index), index, remaining-1]
        end
        index += 1
      end
      element = get(index)
      remaining.times { result << element }
      yield result
    end
    combos[[], 0, n]
  end
  return self
end

#repeated_permutation(n = @size) ⇒ self, Enumerator

When invoked with a block, yields all repeated permutations of length n of elements from the Tuple, and then returns self. A "repeated permutation" is one where any element from the Tuple can appear any number of times, and in any position (not just consecutively)

If no length n is specified, permutations of all elements will be yielded. There is no guarantee about which order the permutations will be yielded in.

If no block is given, an Enumerator is returned instead.

Examples:

t = Erlang::Tuple[5, 6, 7]
t.repeated_permutation(2) { |p| puts "Permutation: #{p}" }

Permutation: [5, 5]
Permutation: [5, 6]
Permutation: [5, 7]
Permutation: [6, 5]
Permutation: [6, 6]
Permutation: [6, 7]
Permutation: [7, 5]
Permutation: [7, 6]
Permutation: [7, 7]
# => Erlang::Tuple[5, 6, 7]

Returns:

  • (self, Enumerator)


1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
# File 'lib/erlang/tuple.rb', line 1044

def repeated_permutation(n = @size)
  return enum_for(:repeated_permutation, n) if not block_given?
  if n < 0
    # yield nothing
  elsif n == 0
    yield []
  elsif n == 1
    each { |element| yield [element] }
  else
    result = []
    perms = lambda do |index|
      0.upto(@size-1) do |i|
        result[index] = get(i)
        if index < n-1
          perms[index+1]
        else
          yield result.dup
        end
      end
    end
    perms[0]
  end
  return self
end

#reverseTuple

Return a new Tuple with the same elements as this one, but in reverse order.

Examples:

Erlang::Tuple["A", "B", "C"].reverse  # => Erlang::Tuple["C", "B", "A"]

Returns:



593
594
595
# File 'lib/erlang/tuple.rb', line 593

def reverse
  return self.class.new(((array = to_a).frozen? ? array.reverse : array.reverse!).freeze)
end

#reverse_each(&block) ⇒ self

Call the given block once for each element in the tuple, from last to first.

Examples:

Erlang::Tuple["A", "B", "C"].reverse_each { |e| puts "Element: #{e}" }

Element: C
Element: B
Element: A

Returns:

  • (self)


486
487
488
489
490
# File 'lib/erlang/tuple.rb', line 486

def reverse_each(&block)
  return enum_for(:reverse_each) unless block_given?
  reverse_traverse_depth_first(@root, @levels, &block)
  return self
end

#rindex(obj) ⇒ Integer #rindex {|element| ... } ⇒ Integer

Find the index of an element, starting from the end of the tuple. Returns nil if no element is found.

Overloads:

  • #rindex(obj) ⇒ Integer

    Return the index of the last element which is #== to obj.

    Examples:

    t = Erlang::Tuple[7, 8, 9, 7, 8, 9]
    t.rindex(8) # => 4
  • #rindex {|element| ... } ⇒ Integer

    Return the index of the last element for which the block returns true.

    Examples:

    t = Erlang::Tuple[7, 8, 9, 7, 8, 9]
    t.rindex { |e| e.even? }  # => 4

    Yields:

    • (element)

      Once for each element, last to first, until the block returns true.

Returns:

  • (Integer)


1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
# File 'lib/erlang/tuple.rb', line 1266

def rindex(obj = (missing_arg = true))
  obj = Erlang.from(obj)
  i = @size - 1
  if missing_arg
    if block_given?
      reverse_each { |element| return i if yield element; i -= 1 }
      return nil
    else
      return enum_for(:rindex)
    end
  else
    reverse_each { |element| return i if element == obj; i -= 1 }
    return nil
  end
end

#rotate(count = 1) ⇒ Tuple

Return a new Tuple with the same elements, but rotated so that the one at index count is the first element of the new tuple. If count is positive, the elements will be shifted left, and those shifted past the lowest position will be moved to the end. If count is negative, the elements will be shifted right, and those shifted past the last position will be moved to the beginning.

Examples:

t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
t.rotate(2)   # => Erlang::Tuple["C", "D", "E", "F", "A", "B"]
t.rotate(-1)  # => Erlang::Tuple["F", "A", "B", "C", "D", "E"]

Parameters:

  • count (Integer) (defaults to: 1)

    The number of positions to shift elements by

Returns:



610
611
612
613
# File 'lib/erlang/tuple.rb', line 610

def rotate(count = 1)
  return self if (count % @size) == 0
  return self.class.new(((array = to_a).frozen? ? array.rotate(count) : array.rotate!(count)).freeze)
end

#sampleObject

Return a randomly chosen element from this Tuple. If the tuple is empty, return nil.

Examples:

Erlang::Tuple[1, 2, 3, 4, 5].sample  # => 2

Returns:

  • (Object)


1228
1229
1230
# File 'lib/erlang/tuple.rb', line 1228

def sample
  return get(rand(@size))
end

#select {|element| ... } ⇒ Tuple Also known as: find_all, keep_if

Return a new Tuple containing all elements for which the given block returns true.

Examples:

Erlang::Tuple["Bird", "Cow", "Elephant"].select { |e| e.size >= 4 }
# => Erlang::Tuple["Bird", "Elephant"]

Yields:

  • (element)

    Once for each element.

Returns:



501
502
503
504
# File 'lib/erlang/tuple.rb', line 501

def select
  return enum_for(:select) unless block_given?
  return reduce(self.class.empty) { |tuple, element| yield(element) ? tuple.add(element) : tuple }
end

#shiftTuple

Return a new Tuple with the first element removed. If empty, return self.

Examples:

Erlang::Tuple["A", "B", "C"].shift  # => Erlang::Tuple["B", "C"]

Returns:



452
453
454
# File 'lib/erlang/tuple.rb', line 452

def shift
  return delete_at(0)
end

#shuffleTuple

Return a new Tuple with the same elements as this one, but randomly permuted.

Examples:

Erlang::Tuple[1, 2, 3, 4].shuffle  # => Erlang::Tuple[4, 1, 3, 2]

Returns:



556
557
558
# File 'lib/erlang/tuple.rb', line 556

def shuffle
  return self.class.new(((array = to_a).frozen? ? array.shuffle : array.shuffle!).freeze)
end

#tuple.slice(index) ⇒ Object #tuple.slice(index, length) ⇒ Tuple #tuple.slice(index..end) ⇒ Tuple Also known as: []

Return specific objects from the Tuple. All overloads return nil if the starting index is out of range.

Overloads:

  • #tuple.slice(index) ⇒ Object

    Returns a single object at the given index. If index is negative, count backwards from the end.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
    t[2]  # => "C"
    t[-1] # => "F"
    t[6]  # => nil

    Parameters:

    • index (Integer)

      The index to retrieve. May be negative.

    Returns:

    • (Object)
  • #tuple.slice(index, length) ⇒ Tuple

    Return a subtuple starting at index and continuing for length elements or until the end of the Tuple, whichever occurs first.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
    t[2, 3]  # => Erlang::Tuple["C", "D", "E"]
    t[-2, 3] # => Erlang::Tuple["E", "F"]
    t[20, 1] # => nil

    Parameters:

    • start (Integer)

      The index to start retrieving elements from. May be negative.

    • length (Integer)

      The number of elements to retrieve.

    Returns:

  • #tuple.slice(index..end) ⇒ Tuple

    Return a subtuple starting at index and continuing to index end or the end of the Tuple, whichever occurs first.

    Examples:

    t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
    t[2..3]    # => Erlang::Tuple["C", "D"]
    t[-2..100] # => Erlang::Tuple["E", "F"]
    t[20..21]  # => nil

    Parameters:

    • range (Range)

      The range of indices to retrieve.

    Returns:



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/erlang/tuple.rb', line 350

def slice(arg, length = (missing_length = true))
  if missing_length
    if arg.is_a?(Range)
      from, to = arg.begin, arg.end
      from += @size if from < 0
      to   += @size if to < 0
      to   += 1     if !arg.exclude_end?
      length = to - from
      length = 0 if length < 0
      return subsequence(from, length)
    else
      return get(arg)
    end
  else
    arg += @size if arg < 0
    return subsequence(arg, length)
  end
end

#sortTuple #sort {|a, b| ... } ⇒ Tuple

Return a new Tuple with the same elements, but sorted.

Overloads:

  • #sortTuple

    Compare elements with their natural sort key (#<=>).

    Examples:

    Erlang::Tuple["Elephant", "Dog", "Lion"].sort
    # => Erlang::Tuple["Dog", "Elephant", "Lion"]
  • #sort {|a, b| ... } ⇒ Tuple

    Uses the block as a comparator to determine sorted order.

    Examples:

    Erlang::Tuple["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
    # => Erlang::Tuple["Dog", "Lion", "Elephant"]

    Yields:

    • (a, b)

      Any number of times with different pairs of elements.

    Yield Returns:

    • (Integer)

      Negative if the first element should be sorted lower, positive if the latter element, or 0 if equal.

Returns:



715
716
717
718
719
# File 'lib/erlang/tuple.rb', line 715

def sort(&comparator)
  comparator = Erlang.method(:compare) unless block_given?
  array = super(&comparator)
  return self.class.new(array)
end

#sort_by {|element| ... } ⇒ Tuple

Return a new Tuple with the same elements, but sorted. The sort order is determined by mapping the elements through the given block to obtain sort keys, and then sorting the keys according to their natural sort order (#<=>).

Examples:

Erlang::Tuple["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
# => Erlang::Tuple["Dog", "Lion", "Elephant"]

Yields:

  • (element)

    Once for each element.

Yield Returns:

  • a sort key object for the yielded element.

Returns:



733
734
735
736
737
738
# File 'lib/erlang/tuple.rb', line 733

def sort_by
  return sort unless block_given?
  block = ->(x) { Erlang.from(transformer.call(x)) }
  array = super(&block)
  return self.class.new(array)
end

#take(n) ⇒ Tuple

Return only the first n elements in a new Tuple.

Examples:

Erlang::Tuple["A", "B", "C", "D", "E", "F"].take(4)
# => Erlang::Tuple["A", "B", "C", "D"]

Parameters:

  • n (Integer)

    The number of elements to retain

Returns:



764
765
766
767
# File 'lib/erlang/tuple.rb', line 764

def take(n)
  return self if n >= @size
  return self.class.new(super)
end

#take_whileTuple, Enumerator

Gather elements up to, but not including, the first element for which the block returns nil or false, and return them in a new Tuple. If no block is given, an Enumerator is returned instead.

Examples:

Erlang::Tuple[1, 3, 5, 7, 6, 4, 2].take_while { |e| e < 5 }
# => Erlang::Tuple[1, 3]

Returns:



792
793
794
795
# File 'lib/erlang/tuple.rb', line 792

def take_while
  return enum_for(:take_while) if not block_given?
  return self.class.new(super)
end

#to_aArray Also known as: to_ary

Return an Array with the same elements, in the same order. The returned Array may or may not be frozen.

Returns:

  • (Array)


1328
1329
1330
1331
1332
1333
1334
1335
1336
# File 'lib/erlang/tuple.rb', line 1328

def to_a
  if @levels == 0
    # When initializing a Tuple with 32 or less elements, we always make
    # sure @root is frozen, so we can return it directly here
    return @root
  else
    return flatten_node(@root, @levels * BITS_PER_LEVEL, [])
  end
end

#transposeTuple

Assume all elements are tuples or arrays and transpose the rows and columns. In other words, take the first element of each nested tuple/array and gather them together into a new Tuple. Do likewise for the second, third, and so on down to the end of each nested Tuple/array. Gather all the resulting Tuples into a new Tuple and return it.

This operation is closely related to #zip. The result is almost the same as calling #zip on the first nested Tuple/array with the others supplied as arguments.

Examples:

Erlang::Tuple[["A", 10], ["B", 20], ["C", 30]].transpose
# => Erlang::Tuple[Erlang::Tuple["A", "B", "C"], Erlang::Tuple[10, 20, 30]]

Returns:

Raises:

  • (IndexError)

    if elements are not of the same size.

  • (TypeError)

    if an element can not be implicitly converted to an array (using #to_ary)



1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
# File 'lib/erlang/tuple.rb', line 1148

def transpose
  return self.class.empty if empty?
  result = Array.new(first.size) { [] }

  0.upto(@size-1) do |i|
    source = get(i)
    if source.size != result.size
      raise IndexError, "element size differs (#{source.size} should be #{result.size})"
    end

    0.upto(result.size-1) do |j|
      result[j].push(source[j])
    end
  end

  result.map! { |a| self.class.new(a) }
  return self.class.new(result)
end

#uniq(&block) ⇒ Tuple

Return a new Tuple with no duplicate elements, as determined by #hash and #eql?. For each group of equivalent elements, only the first will be retained.

Examples:

Erlang::Tuple["A", "B", "C", "B"].uniq      # => Erlang::Tuple["A", "B", "C"]
Erlang::Tuple["a", "A", "b"].uniq(&:upcase) # => Erlang::Tuple["a", "b"]

Returns:



568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/erlang/tuple.rb', line 568

def uniq(&block)
  array = self.to_a
  if block_given?
    if array.frozen?
      return self.class.new(array.uniq(&block).freeze)
    elsif array.uniq!(&block) # returns nil if no changes were made
      return self.class.new(array.freeze)
    else
      return self
    end
  elsif array.frozen?
    return self.class.new(array.uniq.freeze)
  elsif array.uniq! # returns nil if no changes were made
    return self.class.new(array.freeze)
  else
    return self
  end
end

#unshift(object) ⇒ Tuple

Return a new Tuple with object inserted before the first element, moving the other elements upwards.

Examples:

Erlang::Tuple["A", "B"].unshift("Z")
# => Erlang::Tuple["Z", "A", "B"]

Parameters:

  • object (Object)

    The value to prepend

Returns:



441
442
443
# File 'lib/erlang/tuple.rb', line 441

def unshift(object)
  return insert(0, Erlang.from(object))
end

#update_in(*key_path) {|value| ... } ⇒ Tuple

Return a new Tuple with a deeply nested value modified to the result of the given code block. When traversing the nested Tuples and Hashes, non-existing keys are created with empty Hash values.

The code block receives the existing value of the deeply nested key (or nil if it doesn't exist). This is useful for "transforming" the value associated with a certain key.

Note that the original Tuple and sub-Tuples and sub-Hashes are left unmodified; new data structure copies are created along the path wherever needed.

Examples:

t = Erlang::Tuple[123, 456, 789, Erlang::Map["a" => Erlang::Tuple[5, 6, 7]]]
t.update_in(3, "a", 1) { |value| value + 9 }
# => Erlang::Tuple[123, 456, 789, Erlang::Map["a" => Erlang::Tuple[5, 15, 7]]]

Parameters:

  • key_path (Object(s))

    List of keys which form the path to the key to be modified

Yields:

  • (value)

    The previously stored value

Yield Returns:

  • (Object)

    The new value to store

Returns:

See Also:



# File 'lib/erlang/tuple.rb', line 216

#values_at(*indices) ⇒ Tuple

Return a new Tuple with only the elements at the given indices, in the order specified by indices. If any of the indices do not exist, nils will appear in their places.

Examples:

t = Erlang::Tuple["A", "B", "C", "D", "E", "F"]
t.values_at(2, 4, 5)   # => Erlang::Tuple["C", "E", "F"]

Parameters:

  • indices (Array)

    The indices to retrieve and gather into a new Tuple

Returns:



1242
1243
1244
# File 'lib/erlang/tuple.rb', line 1242

def values_at(*indices)
  return self.class.new(indices.map { |i| get(i) }.freeze)
end

#zip(*others) ⇒ Tuple #zip(*others) {|pair| ... } ⇒ nil

Combine two tuples by "zipping" them together. others should be arrays and/or tuples. The corresponding elements from this Tuple and each of others (that is, the elements with the same indices) will be gathered into arrays.

If others contains fewer elements than this tuple, nil will be used for padding.

Examples:

t1 = Erlang::Tuple["A", "B", "C"]
t2 = Erlang::Tuple[1, 2]
t1.zip(t2)
# => Erlang::Tuple[["A", 1], ["B", 2], ["C", nil]]

Overloads:

  • #zip(*others) ⇒ Tuple

    Return a new tuple containing the new arrays.

    Returns:

  • #zip(*others) {|pair| ... } ⇒ nil

    Yields:

    • (pair)

      once for each array

    Returns:

    • (nil)

Parameters:

  • others (Array)

    The arrays/tuples to zip together with this one

Returns:



685
686
687
688
689
690
691
692
# File 'lib/erlang/tuple.rb', line 685

def zip(*others)
  others = others.map { |other| Erlang.from(other) }
  if block_given?
    return super(*others)
  else
    return self.class.new(super(*others))
  end
end