Project

General

Profile

Actions

Bug #19733

closed

Kernel#Rational does not accept prefix 0

Added by sawa (Tsuyoshi Sawada) 11 months ago. Updated 11 months ago.

Status:
Feedback
Assignee:
-
Target version:
-
[ruby-core:113910]

Description

Integer and Rational literals accept prefix 0. There is no difference in this respect.

0b10 # => 2
0b10r # => (2/1)

However, when it comes to Kernel#Integer and Kernel#Rational, the former accepts prefix 0 while the latter does not. This is confusing. And as I do not see any reason they should behave differently, I think it is a bug.

Integer("0b10") # => 2
Rational("0b10") # !> ArgumentError
Actions #1

Updated by sawa (Tsuyoshi Sawada) 11 months ago

  • Description updated (diff)

Updated by mame (Yusuke Endoh) 11 months ago

  • Status changed from Open to Feedback

"Confusing" is not necessarily a bug. What Kernel#Rational accepts is clearly stated in the documentation in BNF style.

https://docs.ruby-lang.org/en/master/Kernel.html#method-i-Rational

There may be room for discussion to make Kernel#Rational accept 0x10, though I personally don't need it. An explanation of a use case would help the discussion.

Updated by sawa (Tsuyoshi Sawada) 11 months ago

mame (Yusuke Endoh) wrote in #note-2:

"Confusing" is not necessarily a bug. What Kernel#Rational accepts is clearly stated in the documentation in BNF style.

https://docs.ruby-lang.org/en/master/Kernel.html#method-i-Rational

I had read that documentation, and thought that perhaps someone is going to mention. The BNF in that documentation is broken as it does not mention the fact that the denominator can take a fractional part.

Rational("1/1.2") # => (5/6)

According to the documentation you mention, the expression above should raise an argument error, contrary to fact. So, that documentation is not reliable any way.

Using your words, either the documentation or the fact I mentioned above in this comment is clearly a bug, if the issue I raised is not.

Updated by sawa (Tsuyoshi Sawada) 11 months ago

@mame (Yusuke Endoh) It seems that you were not aware of the fact that the documentation is wrong. And I hope you share with me the idea that we want the documentation to be correct. I think the reason why there was a mistake in the documentation, and why you have not noticed it, is either because the specification is ad hoc or it was not implemented in the way it was intended or in the way people would normally expect. I believe this has to be solved in some way.

I can say that the current behavior is counter-intuitive. Even though Integer class is not a subclass of Rational class, coercion relation indicates that whatever can be interpreted as an Integer can be interpreted as a Rational but not vice versa. And I think people would normally expect whatever is interpretable by Kernel#Integer is interpretable by Kernel#Rational.

A use case that I can think of where this becomes relevant is an arithmetic program in which some string (from user input or from some data) is attempted to be interpreted using methods like Kernel#Rational or Kernel#Integer one after another (avoiding the use of methods like eval in fear of malicious code). Such program may attempt interpretation of a string by Kernel#Rational, and if it succeeds, go on to attempt interpretation by Kernel#Integer to see if the interpretation can be further narrowed down. However, if a non-decimal integer string is passed to Kernel#Rational and an error is raised, such program would give up attempting interpretation by Kernel#Integer, even though it would succeed, and that input string would be thrown away.

Even more strange is the fact that, in case of hexadecimal 0x (but not with other 0 prefixes), it becomes interpretable again by Kernel#Float. This is a real mess.

Integer("0x10") # => 16
Rational("0x10") # !> ArgumentError
Float("0x10") # => 16.0
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0