Ideas for making Rust easier for Beginners


This should simply be handled in the same way as e.g. v[3..2] is handled. The v[-4..2] is a very rare edge-case anyway and would be bad practice as in intentional code obfuscation.


v[3..2] is clearly and unambiguously empty for all v.

But v[-4..2]? For len<4, converting the isize to the correct usize index overflows unless done carefully, but I guess it has two elements? For len 4 it has two elements, for len 5 it has one element. For len>5 it’s empty. That’s substantially more work to reason about.

If that kind of thing is possible, then anything taking signed indexes needs to deal with it, even if it’s bad style.


Negative indexes is a bad idea. Take a look at the much better D language solution, it uses "-i", where is a contextual variable that’s equal to len().


What you’re asking for, @konstin, is the confounding of two types of operations (forward and backward indexing) into the same value. This will only make reasoning about dynamically computed indices more complicated and error-prone.

There’s no reason to believe that “beginners” would find negative indices easier. If anything, it’s just yet another special case. Just say `v[2 … v.len()-3] if this is what you mean.


Ideas for making Rust easier for Beginners

Maybe make a playpen-based environment where users can also:

  • Report that they are fed up and abandoning attempts (with optional comment). Maybe analysing the “graveyard” database of such snippets may point to the typically tricky, hard-to-get parts.
  • Request help (of a bot and/or a human)
  • Do some exercises from a book sequentially (with automatic tests)? There may be dedicated customized auto-help based on possible error messages when doing them wrong.


+1 This is a cool idea.


Next playpen idea:

Dual pane playpen: library + app.

With this one can experiment with orphan rules, Macros 1.1, etc.

Also users will subconsciously prepare to libify there code from early. Also help requests about creating libraries can have nice playpen links.

Obviously, default view should be single-pane.


Seems like it would be better to just support something like multipart scripts that expand to multiple files. Then you could put more complete multi-file examples into a playpen.


I like the idea of some improved playpen kind of thing, but that idea should be better discussed in its own thread. I’ve just collected my own ideas in this thread to avoid spamming.

Anyways, is the any feedback on my ideas besides generics and negative indices?


Since you asked:

For “Shorten the Compiler’s Type Errors” and “Allow tests to work through visibility and scope borders”, I simply don’t understand the points being made well enough to respond to them. But these both sound like they might be good ideas, so I’d suggest starting separate threads to explain them in more detail with concrete examples for people like me that aren’t bothered by whatever these problems are.

For “From and To in the html docs” I couldn’t quite parse what you were trying to say, but if you’re suggesting some kind of special case in rustdoc for aggregating From impls, To impls, etc in a way that makes the full list of impls more readable then I’m 100% with you on that.


I’m working on making these errors slightly easier to read:


Isn’t the example equivalent to

fn take_iterator(it: impl Iterator) {}

, though?


Sometimes I miss some sort of Iterator comprehension syntax sugar like Python’s or Haskell’s. For example, being able to do the following as sugar for a .filter_map():

let calculated_odds = [calculate(x) for x in foo.iter() if x % 2 == 1];

Also, having this in combination some useful macros for collections such as HashMap, like json! from serde_json:

let m = map!{
  x => y
  for (x, y) in a.iter().zip(b.iter())


There are actually two macros that allow you to do this:

From the main page:

let x: Vec<i32> = gen![i*1000 => i in [1, 2, 3, 4, 5, 6], i % 2 == 0];
assert_eq!(x, vec![2000, 4000, 6000]);

And this one:

Edit: Looks like the first crate doesn’t work on stable, but the second does.


For me the fn foo(x: impl Iterator) syntax is clearer than fn foo(x: <Iterator>)


get this to compile:

fn main() {

    println!("{}", 2.0.sqrt());


fn main() {
   println!("{}", 2.0.sqrt());

The problem here seems to be that the compiler doesn’t know how wide to make 2.0; it compiles if you write 2.0_f32.sqrt() (or _f64). I seem to recall some discussion about infinite-precision integer constant arithmetic the other week, but extending that to floating-point has obvious problems, and to functions that (mathematically ought to) return irrational numbers even more so.

Would it make sense to “just” default to f64 for this sort of thing? Lots of other languages do it that way.


looking at it further, rust already defaults to f64 in a lot of places. mem::size_of_val(&0.0) returns 8, and implementing sqrt as a trait function (playground link) works, with 2.0.root() defaulting to the f64 impl. only on inherent methods, it seems, rustc doesn’t know what to call.


Turns out this is already logged as a compiler bug: