0

I saw a question talk about this:

let i = (-100).abs();
error[E0689]: can't call method `abs` on ambiguous numeric type `{integer}`

And from a post:

{integer} is how rustc prints out the placeholder type for an integer literal. It's not a real type; it needs to collapse to a real iN or uN type to be used.

I think (-100) should be able to inferred or collapse as (-100_i32) automatically.

The following code shows it is possible to achieve the desired behavior if abs is a trait method impl directly on i32, i16, etc.

fn main() {
    let num1 = (-100).foo_abs();     // num1: i32
    let num2 = (-100_i16).foo_abs(); // num2: i16
}

trait FooAbs {
    fn foo_abs(self) -> Self;
}

impl FooAbs for i16 {
    fn foo_abs(self) -> Self {
        if self.is_positive() {
            self
        } else {
            -self
        }
    }
}

impl FooAbs for i32 {
    fn foo_abs(self) -> Self {
        if self.is_positive() {
            self
        } else {
            -self
        }
    }
}

Is there any reason or benefit behind the current design, or is it not implemented in this way for a specific purpose?

cpprust
  • 110
  • 4
  • 1
    It seems like your question is the same as the one you have linked to. If the answer to that question is unclear to you, you could post a comment on that answer asking for clarification. Otherwise please explain how your question is different. – kaya3 Mar 28 '23 at 12:37
  • I don't understand your question. – Chayim Friedman Mar 28 '23 at 12:58
  • 2
    Type inference in Rust is in general not fully specified. It's even explicitly exempt from Rust's stability guarantees. And it does have some quirks, but they never really cause serious problems. If the compiler can't infer a type, just add a type annotation and move on. – Sven Marnach Mar 28 '23 at 13:07
  • 1
    if you ask me rust shouldn't even default integer to i32... – Stargateur Mar 28 '23 at 13:26
  • @Stargateur Why is that, isn't it convenience? That's the most used integer type in most cases. – cpprust Mar 28 '23 at 14:09
  • 1
    In 30 years' time it might not still be the most used, but if Rust defines `i32` as the default now then it can't change it later without breaking existing code. – kaya3 Mar 28 '23 at 14:25
  • 1
    @cpprust Is `i32` really the most used integer type? I use it comparatively rarely in my code. I mostly use `usize` for counts and indices, `u32` for counts when size is a concern, `f64` for floats, `u8` for bytes (e.g. in `&[u8]` or `Vec`). `i32` and `i64` do occur when I need negative numbers, but quite rarely. As a crude measure, I counted the appearance of `u32` and `i32` tokens in a 600kloc in-house codebase, and u32 shows up 4339 times, while i32 occurs 390 times. (Also: usize: 1889, isize: 12, u64: 1863, i64: 383.) – user4815162342 Mar 28 '23 at 14:50
  • 1
    @cpprust i32 is one of the integer type I use the less, I always use unsigned, usize > uXX > fXX >= iXX. But it doesn't matter, default to i32 can create many bug, the choice of integer type in code is not trivial and shouldn't be "default to i32" this is a mistake Rust made cause "but that what C have done since 50 years" well C was wrong and we copy it to "do like other language" but it's create bug in C for a long time, hopefully in Rust this is rarely the case cause rust is way more robust than C at the first place. Also clippy have a lint for it `default_numeric_fallback` – Stargateur Mar 28 '23 at 15:34
  • 1
    Questions closed as duplicates don't need to be deleted. – kaya3 Mar 30 '23 at 13:44
  • @SvenMarnach Without type ascription, just adding the type isn't always so easy. – BallpointBen Mar 30 '23 at 18:13
  • @BallpointBen You can almost always pull out the part of the expression you want to annotate into a let binding. There are a few exceptions, e.g. the loop variable of a for loop can't have a type annotation. You can always use fully qualified syntax to select the right method, though. – Sven Marnach Mar 31 '23 at 08:35

0 Answers0