Bug #4577

(int...float).max should not raise an error

Added by Joey Zhou about 4 years ago. Updated over 2 years ago.

[ruby-core:35754]
Status:Rejected
Priority:Normal
Assignee:Yukihiro Matsumoto
ruby -v:- Backport:

Description

=begin
(int...float).max (without a block) will raise an error:

(({p (1...9.3).max # cannot exclude non Integer end value (TypeError)}))

I don't think it should do so.

int...float is a valid range object. When I construct such range, there's no error message.

The range can call all the Range instance methods. Only when calling single #max, the errmsg seems to tell that the range itself is not valid.

#max with a block will not raise the error:

(({p (1...9.3).max {|a,b| a <=> b} #=> 9}))

I think (1...9.3).max should also return 9( (end_obj-1).ceil ). If you admit the legality of #max(&block), you should also admit #max().
=end


Related issues

Related to Ruby trunk - Bug #4591: (1.5...2).max #=> 1 (Range#max) Closed 04/21/2011
Related to Ruby trunk - Bug #974: Range#max で終了しないことがある Closed 01/04/2009

History

#1 Updated by Masaya Tarui about 4 years ago

  • ruby -v changed from ruby 1.9.2p180 (2011-02-18) [i386-mingw32] to -

=begin
Hi,

I feel that 1.8's Range#max is good.

1.9's Range#max sometimes does strange behavior.

irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.9.3dev (2011-04-11 trunk 31261) [i386-mswin32_100]"
irb(main):002:0> (1..1.2).max
=> 1.2
irb(main):003:0> (1...1.2).max
TypeError: cannot exclude non Integer end value
irb(main):004:0> (1.1..3.2).max
=> 3.2
irb(main):005:0> (1.1..2).max
=> 2
irb(main):006:0> (1.1...2).max
=> 1

(1.1...2).max is 1 ?!!!
I cannot think it is correct result.

Here is 1.8's

irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32]"
irb(main):002:0> (1..1.2).max
=> 1
irb(main):003:0> (1...1.2).max
=> 1
irb(main):004:0> (1.1..3.2).max
TypeError: can't iterate from Float
irb(main):005:0> (1.1..2).max
TypeError: can't iterate from Float
irb(main):006:0> (1.1...2).max
TypeError: can't iterate from Float

Here is better though it is sad not to be able to treat Float.

btw, I have used Range only with Integer :-)
--
Masaya TARUI
No Tool,No Life.
=end

#2 Updated by Yukihiro Matsumoto about 4 years ago

=begin
Hi,

In message "Re: [Ruby 1.9 - Bug #4577]Open.max should not raise an error"
on Fri, 15 Apr 2011 00:02:07 +0900, redmine@ruby-lang.org writes:
|----------------------------------------
|Bug #4577: (int...float).max should not raise an error
|http://redmine.ruby-lang.org/issues/4577

|(int...float).max (without a block) will raise an error:
|
|(({p (1...9.3).max # cannot exclude non Integer end value (TypeError)}))
|
|I don't think it should do so.

OK, you don't think it should do so, then what do you think it should
do? ... makes ranges excludes the end point. When the end point is
floating point number, what should be the max value of the range, that
should be less than (and not equals to) the end point?

I don't think ((end_obj-1).ceil) is not the best value for #max, since
we don't define excluding end point by ((end_obj-1).ceil). yet, at
least.

                        matz.

=end

#3 Updated by Joey Zhou about 4 years ago

=begin
Well, what I mean is ((#max without block)) and ((#max {block})) should act the same way, maybe.

(1...6.3).max {|a,b| a <=> b} # 6

Why this one can iterate from 1 to 6, but not single #max ?

It seems there are two #max, one support #each, and another not.

I think this results in confusion.

Here:

p (1..6.3).last # 6.3, same as (1..6.3).end
p (1..6.3).last(1) # [6]
p (1...6.3).last(1) # [6], well... not [6.3]

two dots, or three dots, return the same array, with the element an int number.

thus #last(n) can return int number, although its end_obj is floating point number,
I think (1...6.3).max returning int 6 is also OK. it can be a rule.

I think the methods' behaviour of Range class should be consistent, when the range contains floating point number.

Joey
=end

#4 Updated by Joey Zhou about 4 years ago

=begin
Ranges with numbers as begin_obj and end_obj can be summarized to four(..and...):

int..int # no problem
float..float # no problem, float has no #succ, cannot iterate
float..int # act as float..float, no problem, no #succ, no iteration
int..float # I think more attention should be paid to this...

I suggest the feature here:

when int..float is used in #cover? #include? #===, there's no problem, just: begin_obj <=> obj and obj <=> end_obj

but when int..float(and int...float) is used in any method requiring iteration, the fractional part of float, may be dropped as scrap, if needed.

(1..5.3).to_a #=> 1,2,3,4,5.to_a #=> 1,2,3,4,5.to_a #=> 1,2,3,4,5.to_a #=> 1,2,3,4.last(1) #=> 5.last(1) #=> [5]

the methods above are all OK, you can say there's a implicit rule: "0.3 is scrap, we dropped it"

but #last and #max:

(1..5.3).last #=> 5.3
(1...5.3).last #=> 5.3
(1..5.3).max #=> 5.3, well, same as #end
hmm, #end, #last(no arg), #max(no block) all act the same, why should we need three methods to tell the end_obj?
(1...5.3).max # ERROR!

(1..5.3).max {|a,b| a <=> b} # 5, fraction-scrap
(1...5.3).max {|a,b| a <=> b} # 5 too

If the single #max follow "fraction-scrap" rule, I think it's better
(1..5.3).max #=> 5
(1...5.3).max #=> 5
(1...5.0).max #=> 4
=end

#5 Updated by Koichi Sasada almost 4 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto

#6 Updated by Yukihiro Matsumoto almost 3 years ago

  • Status changed from Assigned to Rejected

After the discussion with core team members, I see no valid reason to make a change, except for vague feeling.
So I reject it at the moment.

Matz.

Also available in: Atom PDF