rbs icon indicating copy to clipboard operation
rbs copied to clipboard

Add infinity pattern

Open ksss opened this issue 1 year ago • 2 comments

Add a pattern to Array#cycle that returns an Enumerator that loops infinitely, as it is missing.

Whether it loops infinitely or not depends on the receiver and cannot be isolated by overloading.

[1,2,3].cycle.each {} # Return type should be `bot` since it will never return

[].cycle.each {} # Just return `nil`

ksss avatar Apr 09 '24 14:04 ksss

@ksss I'm not sure if adding the bot case here. We don't have bot type with IO#gets while it doesn't return when the stream is closed. (I'm curious if having it improves something, and open to have it if it does.)

soutaro avatar Apr 15 '24 03:04 soutaro

The key point of this issue is that it's not about bot itself, but about the type argument. There is no way to write a test case for [1,2,3].cycle despite it having a return value.

assert_send_type(
  "() -> Enumerator[untyped, untyped]",
  [1,2,3], :cycle
)
# Failure: test_cycle(ArrayInstanceTest):
#   Call trace does not match with given method type: #<struct RBS::Test::CallTrace method_name=:cycle, method_call=<RBS::Test::ArgumentsReturn:@arguments: [], @exit_value: #<Enumerator: [1, 2, 3]:cycle>, @exit_type: :return>, block_calls=[], block_given=false>.
#   <["[Array#cycle] ReturnTypeError: expected `Enumerator[untyped, untyped]` but returns `#<Enumerator: [1, 2, 3]:cycle>`"]> was expected to be empty.

Another perspective is that infinite loops can be a critical issue for applications. If programmers could determine the possibility of infinite loops from type information, they could avoid these problems. If it is known that there is a possibility of returning bot, programmers can avoid calling each from Enumerator[untyped, bot]. However, whether this applies to IO#gets is unclear.

ksss avatar Apr 15 '24 14:04 ksss

I still don't agree having the Enumerator[.., bot] case makes sense.

  1. A method call may not return doesn't mean we should have bot return type.
  2. We cannot use the two Enumerator union cases. We cannot decompose them with is_a?, and the each return type will be nil | bot, which is technically identical to nil.

soutaro avatar May 29 '24 02:05 soutaro

OK make sense! Thank you for reviewing.

ksss avatar May 29 '24 12:05 ksss