Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Why does Rust choose not to provide `for` comprehensions? (langdev.stackexchange.com)
24 points by behnamoh on March 11, 2024 | hide | past | favorite | 16 comments


Amusingly, this actually does exist in Rust, via the `std::array::from_fn` function (which I don't see mentioned in the OP):

    let my_arr = [1, 2, 3, 4, 5];

    let new_arr = std::array::from_fn(|i| my_arr[i] + 1);
    
    assert_eq!([2, 3, 4, 5, 6], new_arr);
And yes, this is producing a fixed-size array on the stack; in this case the length of the array is being inferred based on the type provided in the assertion.

https://doc.rust-lang.org/std/array/fn.from_fn.html



That's interesting, though the type inference seems like spooky action at a distance there: removing an assertion can break code.

I suppose it gives you a way to specify the length in the examples (below), but it seems more ergonomic to take it from the original array.

    let bool_arr = core::array::from_fn::<_, 5, _>(|i| i % 2 == 0);


> seems like spooky action at a distance

Note that this inference is static, and the compiler would tell you if it didn't have something concrete to infer the type from. The type inference is also limited to the function body, so removing the assertion could only ever cause an effect in that single function.


Or declare the type of bool_arr.


Indeed, in which case it looks much cleaner than specifying the length via the turbofish:

    let bool_arr: [bool; 5] = ...


That's true. As a relative novice to Rust, I'm familiar with array types, but I'd need to look up `from_fn`


> the length of the array is being inferred based on the type provided in the assertion

Wow! I hate that with an amount of emotion that surprised me!

Does Rust do this kind of look-ahead inference a lot (specifically for deciding what the result shape/type is for a statement)?


> Does Rust do this kind of look-ahead inference a lot

Yes, but it's important to note that type inference in Rust is function-local. Furthermore, crucially, Rust requires types to be explicitly specified at function boundaries. Altogether this means that you (and the compiler) don't need to look farther than the function signature to figure out a given type.

This means that you can do stuff like this:

    let mut foo = HashMap::new();
    foo.insert("bar", true);
Despite the fact that HashMap is a generic type, nowhere do we need to specify that this particular instance has string keys and Boolean values, because the type of the map is inferred from its usage. In languages with only statement-local type inference, you'd need to specify the type of the elements at the point of construction.


This isn't so bad except in the case where a developer puts off the resolving statement until later in the function, though I imagine (hope) there is almost never a legitimate reason to do that.

Is it theoretically possible to split the resolution into two lines? Then, as a reader, it might not always be obvious at what point the type is fully resolved.

E.g (pseudocode, and also it makes no practical sense since you would have populated it before interrogating it).

    let mut foo = HashMap::new();
    print(foo.containsKey("bar")); // here we've resolved the key type
    print(foo.containsValue(true)); // here we've resolved the value type


> Then, as a reader, it might not always be obvious at what point the type is fully resolved.

This is rarely a problem, because Rust is strict enough that it will tell you if your types aren't lining up like you think they are. And if you're using an editor with LSP support, then you can have inlay hints that reveal the types of all variables if you like.


> inlay hints that reveal the types

Oh, that would go a long way to making me feel less nervous reading code like this.


Of course yes.


I personally prefer the following style instead of comprehensions

        let my_arr = [1, 2, 3, 4, 5];
        my_arr.iter().map(|x| x + 1).for_each(
            |item| println!("The Value of this item is {item}")
        );
the map statement allows for one liners, like list comprehensions, with the added benefit of semantics like being able to chain operations into pipelines.


[flagged]


I gave your comment a dislike for the reason that pasting in responses from chatGPT should not be commin practice here. It’s only polluting the comment section in my opinion.


yep




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: