Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array include? rejects nil arguments #1482

Open
p-datadog opened this issue Jan 27, 2025 · 2 comments
Open

Array include? rejects nil arguments #1482

p-datadog opened this issue Jan 27, 2025 · 2 comments

Comments

@p-datadog
Copy link

The following is valid and sensible Ruby code:

%w,true,.include?(ENV['foo'])

Here, we check if the environment variable is set to a particular value.

Steep rejects this with the following error:

env-include.rb:1:18: [error] Cannot pass a value of type `(::String | nil)` as an argument of type `::String`
│   (::String | nil) <: ::String
│     nil <: ::String
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ %w,true,.include?(ENV['foo'])
                    ~~~~~~~~~~

Detected 1 problem from 1 file

Checking some other cases, steep seems to have its own idea of what can and cannot be in an array that does not match the functionality of Ruby. All of the following uses are rejected by steep:

# mixed types in an array
[1,"X"].include?(nil)

# integers vs floats
[1.5].include?(2)
[2].include?(1.5)
env-include.rb:3:17: [error] Cannot pass a value of type `nil` as an argument of type `(::Integer | ::String)`
│   nil <: (::Integer | ::String)
│     nil <: ::Integer
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ [1,"X"].include?(nil)
                   ~~~

env-include.rb:5:15: [error] Cannot pass a value of type `::Integer` as an argument of type `::Float`
│   ::Integer <: ::Float
│     ::Numeric <: ::Float
│       ::Object <: ::Float
│         ::BasicObject <: ::Float
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ [1.5].include?(2)
                 ~

env-include.rb:7:13: [error] Cannot pass a value of type `::Float` as an argument of type `::Integer`
│   ::Float <: ::Integer
│     ::Numeric <: ::Integer
│       ::Object <: ::Integer
│         ::BasicObject <: ::Integer
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ [2].include?(1.5)
               ~~~
@tk0miya
Copy link
Contributor

tk0miya commented Feb 11, 2025

It seems the argument of Array#include? is defined as Elem (the type of array members). The result came from this definition.
https://github.com/ruby/rbs/blob/master/core/array.rbs#L2185

I can understand the definition because passing a non-string value is meaningless. Therefore I'm okay to detect errors if other types are passed (except nil). I agree that it's too strict to raise an error for a nil value. It's better to loosen the type of argument to Elem?.

BTW, your example let us know another problem between Integer and Float. In the case of numbers, it takes other number types as valid. From this perspective, other types should be accepted.

tk0miya added a commit to tk0miya/rbs that referenced this issue Feb 11, 2025
For example, `Array[Integer]` can take other number types validly:

```
> [1, 2, 3].include? 2.0
=> true
> [1, 2, 3].include? Complex(2)
=> true
> [1, 2, 3].include? Rational(2)
=> true
```

refs: soutaro/steep#1482
@soutaro
Copy link
Owner

soutaro commented Feb 19, 2025

Yeah, this is incompatible with Ruby, intentionally. I think this is actually useful to detect a type error on a method call passing an unexpected object.

  • Java allows passing any Object to List<T>.contains, but only allows String likes in String.contatins -- so it looks like they try to have strict types if possible
  • TypeScript gives strict argument type to includes method of an array

Your ENV example seems reasonable, while I still believes the current type definition is useful too...

Passing some default value looks like another reasonable code to me.

%w,true,.include?(ENV['foo'] || false)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants