Skip to content

Type inference failure (partial hints?) #15960

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

Closed
Earnestly opened this issue Jul 24, 2014 · 6 comments
Closed

Type inference failure (partial hints?) #15960

Earnestly opened this issue Jul 24, 2014 · 6 comments
Labels
A-type-system Area: Type system

Comments

@Earnestly
Copy link

A small issue with hints and type inference, I don't fully grok what's going on so here is some code to better explain what I'm seeing:

fn main() {
    let f: int = std::rand::random() % 100i;
    // Or
    // let f: int = (std::rand::random() % 100i) * 20i;
}    
inf.rs:2:18: 2:37 error: the type of this value must be known in this context
inf.rs:2     let f: int = std::rand::random() % 100i;
                          ^~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

However with:

fn main() {
    let f: int = 100i % std::rand::random(); // works but obviously incorrect
}    

rand::random<int>() is successfully deduced.

Why might this be the case?

@steveklabnik
Copy link
Member

I actually cover this in the guide: http://doc.rust-lang.org/guide.html

Search for "It didn't work! Rust says "the type of this value must be known in this context." "

@Earnestly
Copy link
Author

You also go on to say:

The from_str function takes in a &str value and converts it into something. We tell it what kind of something with a type hint. Remember our type hint with random()? It looked like this:

rand::random::<uint>();

There's an alternate way of providing a hint too, and that's declaring the type in a let:

let x: uint = rand::random();

In this case, we say x is a uint explicitly, so Rust is able to properly tell random() what to generate. In a similar fashion, both of these work:

Which doesn't work...

let guess = from_str::<Option<uint>>("5");
let guess: Option<uint> = from_str("5");

In this case, I happen to prefer the latter, and in the random() case, I prefer the former. I think the nested <>s make the first option especially ugly and a bit harder to read.

It also doesn't explain why 100i std::rand::random(); works but the reverse fails even when I explicitly give it a type.

It seems pretty arbitrary to me atm, sorry if this is simple misunderstanding

@steveklabnik
Copy link
Member

No no, it's cool. If you don't understand, I haven't done my job. I just need to figure out how you don't understand, so I can fix the guide.

When you say 'which doesn't work,' what do you mean, exactly? That last code snippet? Maybe something has changed in Rust in the last week or so, because when I wrote it, it did work.

@Earnestly
Copy link
Author

What do you mean, exactly?

// Rust will fail to infer from the type of `f` that `random()` should be `random<int>();`
let f: int = std::rand::random() % 100i;

// But it will infer it when we do this: (although this is incorrect logically)
let f: int = 100i % std::rand::random();

Thus when you say we can use let x: uint = rand::random(); because "Rust is able to properly tell random() what to generate." we see the context errors. What exactly I mean is exactly where I said "Which doesn't work", directly under the code and paragraph that currently doesn't reflect reality.

If there was something unclear about what I'm trying to demonstrate in my initial effort, I can try clear that up, but right now I feel like I'm repeating myself.

If it did work as you say, then perhaps there is a bug?

@ghost
Copy link

ghost commented Jul 26, 2014

// Rust will fail to infer from the type of `f` that `random()` should be `random<int>();`
let f: int = std::rand::random() % 100i;

rust cannot infer the type of std::rand::random(). Explicitly saying that f will be an int just means that it knows that the eventual type of std::rand::random() % 100i will be an int, so it knows that the signature for the type T returned by std::rand::random() must be T: Rand + Rem<int, int>, but any type can fit this signature, it is not exclusive to int.

To prove this, let's make a hypothetical type Foo.

struct Foo {
    bar: int
}
impl Rand for Foo {
    fn rand<R: Rng>(_: &mut R) -> Foo {
        Foo {
            bar: 4 //chosen by fair dice roll.
                   //guaranteed to be random.
        }
    }
}
impl Rem<int, int> for Foo {
    fn rem(&self, rhs: &int) -> int {
        self.bar % *rhs
    }
}

Now you're left with a conundrum, because std::rand::random() in your example could also be a Foo. To solve this, you can do:

let random_number: int = std::rand::random();
let f = random_number % 100;

Or you can do:

let f = std::rand::random::<int>() % 100;

In these cases you are explicitly saying what std::rand::random() should return. There is no ambiguity.

// But it will infer it when we do this: (although this is incorrect logically)
let f: int = 100i % std::rand::random();

In this case, since there is a known type on the left side of the remainder operator, it becomes a lot easier for rust to infer the types of the rest of the line. 100i is an int. int implements the Rem trait (for the remainder operator) as Rem<int, int>. This means that the right hand side of the remainder operator is going to be an int (thus it can infer that std::rand::random() will be an int) and that the return value is also going to be an int (thus it can infer that f is going to be an int). There is absolutely no ambiguity in what the types are going to be.

@Earnestly
Copy link
Author

Ah, thanks. This explanation makes sense.

Closing as the issue now unrelated to Rust's inference

bors added a commit to rust-lang-ci/rust that referenced this issue Nov 27, 2023
Replace `option.map(cond) == Some(true)` with `option.is_some_and(cond)`

Extracted from rust-lang#118253.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system
Projects
None yet
Development

No branches or pull requests

3 participants