Interaction of user-defined and integral fallbacks with inference


It is certainly the conservative choice.


@Gankro, can you elaborate a bit more on how you had hoped to use defaults to improve ergonomics?


@nikomatsakis Oh sorry, missed this message!

Specifically the std lib currently has some curiously hardcoded type parameters just so simple things will “just work”. In particular, HashMap::new hardcodes SipHash. With default types we could replace these hardcodes in favour of just a default on HashMap and it should Just Work.

This completely avoids the question at hand though, since defaulting random integers for the std APIs would be Dumb for the most part.

Although in the future you could imagine adding a default param for the size of the hash, which would indeed default to u64.


Actually BitVec and BitSet (now external crates) do something similar to HashMap but with the size of the backing blocks. Right now they hardcode u32 for almost everything to keep everyone Just Working from std. However in this case i32 isn’t an applicable choice (relevant trait only impl’d for unsigned types).


I’ve always expected that Rust would go in the “flexible literal” direction, because it’s the right thing to do. If the compiler can choose the correct size for you in some cases, that’s a huge benefit to prototyping. As it is now, even a medium size codebase is hard to refactor because all the types are concrete.

This can be extended further - strings can just be written in quotes like "Hello World" and the type system figures out if you want a String or &str or a Rope or what have you.


I always considered the default integer fallback to be a last-resort kind of thing. As such I would expect the user-defined fallback to always take priority over the i32 fallback, because if I, as a user, really wanted a i32, I would have used the suffix. This means in the first example I would expect u64, and in the second I would expect i32. I pick the DWIM option. My second choice would be the ‘user-defined default always’ option.


While this would be nice for prototyping, Rust isn’t really shooting for being a prototyping language. We really try to make costs explicit, and all of these options have very different costs.


You can’t just prototype a Rust project in Ruby, what else are you going to prototype a Rust project in? A scripting language with an ownership system?


Why not?


That’s like prototyping a Rust project by putting everything inside an Rc

it actually doesn’t work because you’ll have to think about ownership eventually


You may be thinking of productyping – that’s a weird bastard of prototyping and building a product. The end result usually fails both as a prototype and product (though there have been rare exceptions to this rule).

With prototyping you don’t want to think about ownership. Or lifetimes. Or types. Or anything that doesn’t directly relate to the thing that you want to prototype.


Let’s say I want to prototype a convolutional neural net library written in Rust. There’s already C++ implementations. How does Ruby help me?


You don’t need to prototype if there are already implementations. In that case you can choose one and port.


Not really, because the C++ implementation will have classes, so you need to organize your Rust implementation differently and probably more Rusty instead of just emulating classes.

Because of this, you may not know the concrete types you’re using in your Rust implementation (that, and because you can’t use the C++ libraries), but you shouldn’t have to worry about what type you’re using until it becomes a bottleneck.


The architecture of a prototype isn’t supposed to inform the architecture of the final product. The only purpose of a prototype is to show that the product can be built at all, and to figure out what the user requirements are. If you’re worried about implementation details, you’re not prototyping.


Yes, but when you get to that stage, Rust is really painful to use because you have to keep changing types.

Do you want to keep things in an Arc<T> instead of Rc<T> because you’re multi-threaded now? Have to change the types EVERYWHERE. That’s what’s painful about developing in Rust, there’s no IDE to automatically refactor things like this.


For that specific purpose, can’t you basically get by with just some basic regex search and replace across files (e.g. sed)? Of course, that’s grossly insufficient for a large number of generally useful types of refactoring… (not that I really want to see such useful functionality locked into a specific IDE - would be better to have a general purpose library with a CLI as one supported interface.)


I think we all should stop getting hung up on terminology. Probably you mean explorative programming, which is quite common in Rust, since it is quite a new language.

Ironically (though for good reason) Rust is opinionated in the sense that it often optimizes for readable ‘done’ code, sometimes at the expense of more work when producing it.

I think this is good on balance, because usually (hopefully?) code will be read more than written. In any event, I hope that once Rust IDEs become more powerful, those pain points will vanish.


After some discussion in the lang subteam mtg yesterday, the consensus was that we should adopt the most conservative strategy to start, leaving room for later changes. One advantage of this is that adding this feature may cause compilation errors in the wild (though I think crater runs showed no such errors in, at least at that time) but will not trigger silent changes to behavior.