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

ParseIntError and ParseFloatError does not allow to introspect the cause #22639

Closed
nagisa opened this issue Feb 21, 2015 · 26 comments · Fixed by #84910
Closed

ParseIntError and ParseFloatError does not allow to introspect the cause #22639

nagisa opened this issue Feb 21, 2015 · 26 comments · Fixed by #84910
Labels
A-floating-point Area: Floating point numbers and arithmetic B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@nagisa
Copy link
Member

nagisa commented Feb 21, 2015

The only way to introspect reason of .parse failure is to compare to error messages returned by description or use the following code snippet:

let overflow = "1231123123123123".parse::<u32>().err().unwrap();
let underflow = "-1231123123123123".parse::<i32>().err().unwrap();
match "999999999999".parse::<u32>() {
    Ok(n) => println!("{}", n),
    Err(ref e) if *e == overflow => println!("Overflow"),
    Err(ref e) if *e == underflow => println!("Underflow"),
    _ => panic!("wow, no introspection, very convenience")
}
@alexcrichton
Copy link
Member

Note that this was purposefully done to avoid adding extra #[stable] surface for now. It should be able to expose this information through an enum in the future, for example.

@steveklabnik
Copy link
Member

Triage: no change here.

@rust-lang/libs is the intention still to change this to an enum of some kind in the future?

@brson brson added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label May 31, 2016
@Seeker14491
Copy link
Contributor

Any reason to postpone this further?

@BurntSushi
Copy link
Member

@Seeker14491 I don't think it's postponed. I think someone just needs to propose an API?

@phungleson
Copy link
Contributor

Hey, we already have an enum IntErrorKind, just want to check if anything still need to be done to make it pub

rust/src/libcore/num/mod.rs

Lines 2769 to 2774 in fc02736

enum IntErrorKind {
Empty,
InvalidDigit,
Overflow,
Underflow,
}

@gypsydave5
Copy link

I just brushed up against this issue while demoing the guessing game example from the Rust Book - seemed like an easy thing to show off matching on the error kind, but turned out not so much!

@Mark-Simulacrum Mark-Simulacrum added the C-feature-request Category: A feature request, i.e: not implemented / a PR. label Jul 22, 2017
@frontsideair
Copy link

I also wanted to match IntErrorKind::Empty in the number game to abort on EOF, turned out to be impossible.

@sfackler
Copy link
Member

@frontsideair you can just check if the string's empty before parsing, right?

@frontsideair
Copy link

I guess, but it was a fun exercise in pattern matching.

@dtolnay
Copy link
Member

dtolnay commented Nov 19, 2017

I see that checking for empty has come up in the context of the guessing game tutorial. Could somebody make a list of use cases from real code that needs to be able to distinguish between the following other ParseIntError cases?

  • invalid digit
  • number too large to fit in target type
  • number too small to fit in target type

In the event that empty is the only one we ever need to introspect for, I would prefer to close this and instead recommend to check == "" before parsing.

@ranma42
Copy link
Contributor

ranma42 commented Nov 19, 2017

It can be convenient to distinguish too large/too small numbers when accepting configuration parameters that the code will later sanitize by clamping to a valid range. Specifically, they make it possible to perform saturation of the parsed value before it is passed on.

Example: the valid range of offsets is -10..+10, therefore the application stores it in an i8. When the value it outside of the -10..+10 range the app would like to warn the user and proceed with the nearest legitimate value.

Without the ability to discriminate if the number is too big/small, it is not possible to determine what is the nearest legitimate value.

@dtolnay
Copy link
Member

dtolnay commented Nov 19, 2017

@ranma42 do you think that use case would be solved by rust-lang/rfcs#928?

use std::num::Saturating;

fn main() {
    let s = "-999";
    let n = match s.parse::<Saturating<i8>>()?.0 {
        std::i8::MIN ... -11 => { println!("saturating"); -10 }
        11 ... std::i8::MAX => { println!("saturating"); 10 }
        n => { println!("in range"); n }
    };
    println!("n={}", n);
}

@ranma42
Copy link
Contributor

ranma42 commented Nov 20, 2017

Yes, that use case would be covered if Rust had the ability to parse a Saturating<i8> (and in a convenient way, too!)

@amosbatto
Copy link

amosbatto commented Apr 7, 2018

The only way I found around this problem was to do something ugly like this:

match my_str.parse::<i32>() {
	Ok(x) => {my_int = x;},
	Err(e) => {
		if e.to_string() == "invalid digit found in string" {
			println!("Only positive integers are allowed!");
		}
		else if e.to_string() == "number too large to fit in target type" {
			println!("Number is too large!");
		}
		else if e.to_string() == "number too small to fit in target type" {
			println!("Number is too small!");
		}
		else if e.to_string() == "cannot parse integer from empty string" {
			println!("Number is empty!");
		}
	}
}

What is so annoying is that println!("{:?}", e) shows me ParseIntError { kind: InvalidDigit }, but kind is private so we can't access it. Either kind should be made public or a kind() function should be implemented to access to.

@Clockwork-Muse
Copy link

I'm doing custom type parsing (something like this: X+123789Y-3453), and I'd actually like to map the errors into my own custom error type. Yes, I could implement my own integer parsing, but that would defeat the purpose of having a built-in integer parser.

My map would be something like this:

  • Empty -> MyInvalid (because the whole thing isn't empty, just one of the number portions)
  • Underflow/Overflow -> MyUnderflow/MyOverflow (although I'd be fine with just overflow, a la checked_)
  • Invalid -> MyInvalid

....except I can't do that at the moment without resorting to @amosbatto 's trick. It also makes testing very difficult, because I can't tell what error I got back (except by checking the string).

@eopb
Copy link
Contributor

eopb commented Nov 27, 2018

Hello everyone. My PR fixes this issue and has been merged.

Use the feature flag #![feature(int_error_matching)] in nightly to try it out.

@jonas-schievink jonas-schievink added B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC and removed C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Apr 22, 2019
@tspiteri
Copy link
Contributor

If this is to be stabilized, I think that the terminology has to be improved: IntErrorKind uses Underflow to refer to negative overflow, but underflow usually means when the absolute value of a floating-point number is so small it becomes 0 (or a subnormal).

@JarrettBillingsley
Copy link

JarrettBillingsley commented Oct 8, 2019

Maybe PosOverflow and NegOverflow?

@getreu
Copy link

getreu commented Nov 6, 2019

This will also solve my use case described in #39381.

@hellow554
Copy link
Contributor

hellow554 commented Feb 3, 2020

What is missing to make it stable?

@jyn514
Copy link
Member

jyn514 commented Feb 4, 2020

I would find this useful for NonZeroUsize::from_str() to distinguish between "0" and an invalid number.

@KodrAus KodrAus added I-nominated Libs-Tracked Libs issues that are tracked on the team's project board. A-floating-point Area: Floating point numbers and arithmetic labels Jul 31, 2020
@Lucretiel
Copy link
Contributor

Before stabilizing, would it be very complicated to additionally add the byte index where parsing failed? I can imagine that information being useful to an introspector (for example, to print a verbose rust-like arrow pointing to the exact location of the parse failure).

@eopb
Copy link
Contributor

eopb commented Dec 4, 2020

Before stabilizing, would it be very complicated to additionally add the byte index where parsing failed? I can imagine that information being useful to an introspector (for example, to print a verbose rust-like arrow pointing to the exact location of the parse failure).

Should be easy to do. I will probably open a PR with that soon so people discuss it.

@kennytm
Copy link
Member

kennytm commented May 4, 2021

It has been over half a year since #77640 (review), and the indexing question is rejected in #79728 (review), so I guess we can submit another stabilization attempt? 😉

@bors bors closed this as completed in 75ed342 Jun 22, 2021
facebook-github-bot pushed a commit to facebook/errpy that referenced this issue Jan 10, 2023
Summary:
Here we improve the following:
 * The test case for long integers (big integers)
 * We have to use an unusual workaround to detect integer overflow of the `parse::<isize>` function as Meta is on a version of rust < 2022.
 * The workaround is documented and there is a todo as follows:
```
// TODO: use ParseIntError.kind() to detect integer overflow of
// parse of const_value when Meta is on rust 2022.
// In rust 2021 ParseIntError.kind is private
// For now, store an overflow Err from parsing a large integer
// Adapted from rust-lang/rust#22639
// and uutils/coreutils#2882
```

This would seem to be the recommended workaround for detecting integer overflow.

Reviewed By: stroxler

Differential Revision:
D42407915

Privacy Context Container: L1152058

fbshipit-source-id: 049dd6c74305fe193131fd1ea2ad72a0965d253a
@Sol-Ell
Copy link

Sol-Ell commented Oct 17, 2023

It seems int_error_matching has been stabilized, but what about float error matching? Maybe there are reasons for not to stabilize it?

@eopb
Copy link
Contributor

eopb commented Oct 17, 2023

There's currently no float_error_matching feature but I don't think there's anything blocking someone from making one. Someone would need to propose an API and leave it as an unstable feature for some time before stabilizing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-floating-point Area: Floating point numbers and arithmetic B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.