5 ms·
This type inference at a distance thing is unsettling to me. Adding v[y]; much later in the function (after your debugs) quietly changes everything abov
by xscott 6y ago
This type inference at a distance thing is unsettling to me. Adding
v[y];
much later in the function (after your debugs) quietly changes everything above it...
- pornel 6y agoType inference works only when the types are unambiguous - arrays don't support indexing by anything else. With strict typing and very few implicit conversions in the language it works very well without surprises. You can still declare types ahead of time if you want to.
- xscott 6y ago> Type inference works only when the types are unambiguous It looks to me like when the types are ambiguous (because nothing placed a restriction on them), integer literals become 32 bit and floating literals become 64 bit. Then quietly, later when you add a restriction, the code above (which you've already worked through one line at a time with debug statements and all) changes from underneath you. > You can still declare types ahead of time if you want to. When the implicit stuff is surprising, I'd rather it wasn't ever implicit.
- steveklabnik 6y agopornel is right, but to be extra clear: if that happened and the types were mis-matched, it’s not very quiet: you’d get a compiler error. We don’t implicitly coerce numerics.
- xscott 6y agoI think the i32 default for integer literals stands in contrast to the otherwise solid choices for numerics on builtin types in Rust.
- steveklabnik 6y agoWhat would you prefer?
- xscott 6y agoPersonally I would prefer i64, but the following are defensible: - Treat it as a special arbitrary precision type, similar to Go - Choose isize because it's the native size for the platform - Make it a compile error when the type can't be inferred The rationale for i32 in RFC 0212 is basically, "well C compilers usually do this", and some hand waving about cache (why not i16 or i8 then?!?). Then they chose f64 instead of f32 for floating literals, which undermines the cache argument. So really, Rust did it because C compilers do it, and C compilers do it to simplify porting old software, which doesn't apply to Rust.
- steveklabnik 6y agoWe did option 3, and it made examples and docs very difficult. Option 1 is not acceptable given Rust's attitude towards allocation. We could do option 2, it's true. > The rationale for i32 in RFC 0212 is basically, "well C compilers usually do this" I don't agree with this; but it doesn't really matter at the end of the day, it's been years and this can't really change. Regardless, I appreciate the elaboration :) It helps me understand the way others think about Rust.
- xscott 6y agoYeah, I realize none of this can change. However, if there is ever a breaking version 2.0 on the roadmap, I'll tell you the features which keep me from actually using Rust. The i32 is pretty insignificant. :-)
- steveklabnik 6y agoThere is no plans at this time, but I'm always interested in hearing what folks have to say...
- shigeo 6y agoTangentially, Rust goes well out of its way to avoid "type inference at a distance". For example, unlike Haskell or most MLs, type inference will not work across a function boundary.
- xscott 6y agoHere's one that caught me off guard: #[derive(Debug)] struct Foo<T> { pub bar: T } fn hmm<T>(x: T) -> Foo<T> { Foo { bar: x } } fn main() { let f:Foo<f32> = hmm(1.23); print!("got: {:?}\n", f); } So maybe that's not crossing function boundaries, but the type for the generic "hmm" function as the rvalue is being inferred from the explicitly declared type of the lvalue. I know it's pointless to try and change anyone's mind about this, but I personally find it unsettling :-)