ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges
@ 2022-02-10  7:35 zverok (Victor Shepelev)
  2022-03-09 22:22 ` [ruby-core:107807] [Ruby master Bug#18580] Range#include? inconsistency for beginless " jeremyevans0 (Jeremy Evans)
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: zverok (Victor Shepelev) @ 2022-02-10  7:35 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been reported by zverok (Victor Shepelev).

----------------------------------------
Bug #18580: Range#include? inconsistency for String ranges
https://bugs.ruby-lang.org/issues/18580

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:107807] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
@ 2022-03-09 22:22 ` jeremyevans0 (Jeremy Evans)
  2022-08-18  5:21 ` [ruby-core:109524] " matz (Yukihiro Matsumoto)
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: jeremyevans0 (Jeremy Evans) @ 2022-03-09 22:22 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by jeremyevans0 (Jeremy Evans).


This was discussed during the February 2022 developer meeting, and @matz said he needs more time to consider it.

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-96735

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109524] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
  2022-03-09 22:22 ` [ruby-core:107807] [Ruby master Bug#18580] Range#include? inconsistency for beginless " jeremyevans0 (Jeremy Evans)
@ 2022-08-18  5:21 ` matz (Yukihiro Matsumoto)
  2022-08-18  9:19 ` [ruby-core:109536] " nobu (Nobuyoshi Nakada)
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: matz (Yukihiro Matsumoto) @ 2022-08-18  5:21 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by matz (Yukihiro Matsumoto).


I once thought about removing `each`+`succ` semantics from `include?` altogether for simplicity, but it is too big incompatibility.
So I decided to make `include?` to raise exception for beginless/endless non-numeric ranges.

Matz.
 

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98693

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109536] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
  2022-03-09 22:22 ` [ruby-core:107807] [Ruby master Bug#18580] Range#include? inconsistency for beginless " jeremyevans0 (Jeremy Evans)
  2022-08-18  5:21 ` [ruby-core:109524] " matz (Yukihiro Matsumoto)
@ 2022-08-18  9:19 ` nobu (Nobuyoshi Nakada)
  2022-08-19 21:50 ` [ruby-core:109580] " jeremyevans0 (Jeremy Evans)
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: nobu (Nobuyoshi Nakada) @ 2022-08-18  9:19 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by nobu (Nobuyoshi Nakada).


matz (Yukihiro Matsumoto) wrote in #note-3:
> So I decided to make `include?` to raise exception for beginless/endless non-numeric ranges.

I understood that all non-numeric ranges raise `ArgumentError`.
Only beginless/endless ranges?


----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98707

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109580] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (2 preceding siblings ...)
  2022-08-18  9:19 ` [ruby-core:109536] " nobu (Nobuyoshi Nakada)
@ 2022-08-19 21:50 ` jeremyevans0 (Jeremy Evans)
  2022-08-20  3:05 ` [ruby-core:109582] " nobu (Nobuyoshi Nakada)
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: jeremyevans0 (Jeremy Evans) @ 2022-08-19 21:50 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by jeremyevans0 (Jeremy Evans).


nobu (Nobuyoshi Nakada) wrote in #note-4:
> matz (Yukihiro Matsumoto) wrote in #note-3:
> > So I decided to make `include?` to raise exception for beginless/endless non-numeric ranges.
> 
> I understood that all non-numeric ranges raise `ArgumentError`.
> Only beginless/endless ranges?

Assuming @matz only wants this behavior change for beginless/endless non-numeric ranges, I submitted a pull request to implement that: https://github.com/ruby/ruby/pull/6261

Beginless ranges other than those having a string end already raised TypeError in this case, and I think that makes the most sense, so I used TypeError for the exception.

I don't think we should change `Range#include?` behavior for ranges with both a begin and an end, as that is likely to break a substantial amount of existing code.

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98752

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109582] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (3 preceding siblings ...)
  2022-08-19 21:50 ` [ruby-core:109580] " jeremyevans0 (Jeremy Evans)
@ 2022-08-20  3:05 ` nobu (Nobuyoshi Nakada)
  2022-08-20  3:21 ` [ruby-core:109583] " jeremyevans0 (Jeremy Evans)
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: nobu (Nobuyoshi Nakada) @ 2022-08-20  3:05 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by nobu (Nobuyoshi Nakada).


jeremyevans0 (Jeremy Evans) wrote in #note-5:
> Assuming @matz only wants this behavior change for beginless/endless non-numeric ranges, I submitted a pull request to implement that: https://github.com/ruby/ruby/pull/6261

OK, I just thought he was saying removing special handling of String all in the middle of the discussion.

About the implementation, how about splitting the function by `string_use_cover`?

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98755

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109583] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (4 preceding siblings ...)
  2022-08-20  3:05 ` [ruby-core:109582] " nobu (Nobuyoshi Nakada)
@ 2022-08-20  3:21 ` jeremyevans0 (Jeremy Evans)
  2022-08-20  3:32 ` [ruby-core:109584] " nobu (Nobuyoshi Nakada)
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: jeremyevans0 (Jeremy Evans) @ 2022-08-20  3:21 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by jeremyevans0 (Jeremy Evans).


nobu (Nobuyoshi Nakada) wrote in #note-6:
> About the implementation, how about splitting the function by `string_use_cover`?

That seems like a good idea to me.  I'll update the pull request to use that approach.

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98756

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109584] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (5 preceding siblings ...)
  2022-08-20  3:21 ` [ruby-core:109583] " jeremyevans0 (Jeremy Evans)
@ 2022-08-20  3:32 ` nobu (Nobuyoshi Nakada)
  2022-08-20 13:06 ` [ruby-core:109597] " zverok (Victor Shepelev)
  2023-03-17  4:30 ` [ruby-core:112924] " mame (Yusuke Endoh) via ruby-core
  8 siblings, 0 replies; 10+ messages in thread
From: nobu (Nobuyoshi Nakada) @ 2022-08-20  3:32 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by nobu (Nobuyoshi Nakada).


This was my attempt.
https://github.com/nobu/ruby/tree/nonnumeric-range-include_p

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98759

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:109597] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (6 preceding siblings ...)
  2022-08-20  3:32 ` [ruby-core:109584] " nobu (Nobuyoshi Nakada)
@ 2022-08-20 13:06 ` zverok (Victor Shepelev)
  2023-03-17  4:30 ` [ruby-core:112924] " mame (Yusuke Endoh) via ruby-core
  8 siblings, 0 replies; 10+ messages in thread
From: zverok (Victor Shepelev) @ 2022-08-20 13:06 UTC (permalink / raw
  To: ruby-core

Issue #18580 has been updated by zverok (Victor Shepelev).


TBH, my position is that:

1. I don't see why non-numeric `Range#include?` should be prohibited if it is possible to calculate. One example: `Date.new(2022, 8, 1)...Date.new(2022, 9, 1)` currently has different semantics for `cover?` (covers any `Date` **and** `DateTime` inside the period) and `include?` (does this _sequence_ of dates _include_ the target date?); both are clear and useful.
2. I don't see why we need _any_ specialization for `String` ranges: their behavior should be just generic, like any other range.

I am honestly lost now.

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-98779

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:112924] [Ruby master Bug#18580] Range#include? inconsistency for beginless String ranges
  2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
                   ` (7 preceding siblings ...)
  2022-08-20 13:06 ` [ruby-core:109597] " zverok (Victor Shepelev)
@ 2023-03-17  4:30 ` mame (Yusuke Endoh) via ruby-core
  8 siblings, 0 replies; 10+ messages in thread
From: mame (Yusuke Endoh) via ruby-core @ 2023-03-17  4:30 UTC (permalink / raw
  To: ruby-core; +Cc: mame (Yusuke Endoh)

Issue #18580 has been updated by mame (Yusuke Endoh).


Unfortunately, this change broke an existing program: #19533.

The lesson here is that it would be best to avoid changing any behavior just for the sake of consistency unless it is proven that the behavior actually confuses a large number of people.

----------------------------------------
Bug #18580: Range#include? inconsistency for beginless String ranges
https://bugs.ruby-lang.org/issues/18580#change-102445

* Author: zverok (Victor Shepelev)
* Status: Closed
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
The follow-up of #18577.

`Range#include?` is [specialized for strings](https://github.com/ruby/ruby/blob/master/range.c#L1782). For all I can tell, this behavior is relatively new: it emerged when switching `#===` to use `#cover?` instead of `#include?`:
* in 2.6, it was decided that String Ranges should continue to use `#include?` (#14575)
* ...but in 2.7, it was decided that they should use `#cover?` as all others (#15449)

The "despecialization" in 2.7 was actually done by adding more specialization in `range_include_internal`.

This leads to the following:
```ruby
# default Range behavior:
(..Date.today).include? Date.today
# (irb):10:in `each': can't iterate from NilClass (TypeError)

# String Range behavior:
(..'z').include?('w')
# => true 
```

Why I think **it is bad**:
1. This is a leftover of the relatively recent change; why it is 3 versions old, I doubt there is a lot of code relying on this quirk (only beginless ranges are affected)
2. The more "invisible specialization", the more possibility of bugs (as #18577 shows)
3. It is easy to stumble upon while learning Ruby/experimenting (strings and ranges are the most basic objects to be seen in many examples and courses), and to become confused, because there is no reasonable explanation for the semantics other than "well... for String, it is so"
4. It *can* be said that the String ranges behavior have the same specialization as Numeric ones, but it is not so; while Numeric Ranges specialization is long-living legacy, it is at least consistent (`#include?` just behaves like `#cover?` for them, always):

Numerics:
```ruby
(1...3).include? 1.5
# => true, like #cover?

(...3).include? 1.5
# => true, same, the explanation is "just like #cover?"
```
Strings:
```ruby
('a'..'z').include?('ww')
# => false, like #include? for any other type

(..'z').include?('ww')
# => true, this is deeply confusing
```



-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-03-17  4:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-02-10  7:35 [ruby-core:107547] [Ruby master Bug#18580] Range#include? inconsistency for String ranges zverok (Victor Shepelev)
2022-03-09 22:22 ` [ruby-core:107807] [Ruby master Bug#18580] Range#include? inconsistency for beginless " jeremyevans0 (Jeremy Evans)
2022-08-18  5:21 ` [ruby-core:109524] " matz (Yukihiro Matsumoto)
2022-08-18  9:19 ` [ruby-core:109536] " nobu (Nobuyoshi Nakada)
2022-08-19 21:50 ` [ruby-core:109580] " jeremyevans0 (Jeremy Evans)
2022-08-20  3:05 ` [ruby-core:109582] " nobu (Nobuyoshi Nakada)
2022-08-20  3:21 ` [ruby-core:109583] " jeremyevans0 (Jeremy Evans)
2022-08-20  3:32 ` [ruby-core:109584] " nobu (Nobuyoshi Nakada)
2022-08-20 13:06 ` [ruby-core:109597] " zverok (Victor Shepelev)
2023-03-17  4:30 ` [ruby-core:112924] " mame (Yusuke Endoh) via ruby-core

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).