rbs
rbs copied to clipboard
The `range[T]` type definition is to restrictive
The current definition, type range[T] = Range[T] | _Range[T] is mostly correct, except it implicitly requires T to implement <=>: Range cannot be constructed unless T defines <=>. This imposes the <=> limitation on _Range[T], which doesn't actually require it:
MyInt = Struct.new(:to_int)
MyCmpInt = Struct.new(:to_int) do
def <=>(rhs) = to_int <=> rhs.to_int
end
MyRange = Struct.new(:begin, :end, :exclude_end) do
alias exclude_end? exclude_end
end
rng1 = MyInt.new(1)..MyInt.new(2) #=> bad value for range (ArgumentError)
rng2 = MyCmpInt.new(1)..MyCmpInt.new(2) #=> ok!
myrng1 = MyRange.new(MyInt.new(1), MyInt.new(2)) #=> ok!
myrng2 = MyRange.new(MyCmpInt.new(1), MyCmpInt.new(2)) #=> ok!
This is particularly relevant for functions which accept range[int] (or range[int?]), such as String#[]:
puts "hello world"[rng2] #=> el
puts "hello world"[myrng1] #=> el
puts "hello world"[myrng2] #=> el
The current definition would preclude myrng1 from being a valid argument, as MyInt doesn't define <=>. The solution, I think, is to change range[T]'s definition:
type range[T] = Range[T & Comparable::_WithSpaceshipOperator] | _Range[T]