Most common silly mistakes

I still regularly forget the '!' for println! and leave out the mut in

let x = Vec::new();

Does anyone else do this, or is it just me?

4 Likes

I rarely forget the ! behind macros, but I do almost always forget the mut after let where needed. It's not a huge issue though, as the compiler error is pretty clear.

Another mistake I often make is to omit or errorneously add a semicolon. But these issues are also easy to fix. (Just for the record: I like the way semicolons behave in Rust!)

9 Likes

I forget the let mut all the time. I rely on my editor (Sublime + Rust Enhanced) to add it for me — it has a button to apply fixes suggested by rustc.

I got used to using the fix suggestion so much that sometimes I intentionally don't bother getting details right, like adding imports or dereferencing function arguments, because I know the compiler will guess what I mean and offer an auto fix.

I'm also often bothered by lack of ; in:

let foo = {
   2+2
}

}; is not needed after an if {}, and not allowed after struct X {}, so let = {}; bothers me (even though I know Rust's grammar and realize why it's like that).

And I write:

match x {
   1 => foo();
   2 => bar();
}

all the time.

5 Likes

I almost always misplace the <> with impl of generic struct/trait and also have trouble to remember where to place the turbofish ::<>, before or after the (). It is easy, but I always have to think twice or more before to get it right! :relaxed:

1 Like

I often do this, too.

And I write println!(x) instead of println!("{}", x). (used to print(x) in Python)

Sometimes I use dbg! because it's shorter, but I put it in the wrong place or forget to add & inside, so it consumes the variable, which is used later.

Incompatible return types are quite common, for example an if/else returns T whereas it should return Result<T>.

Another one is to move a bunch of structs/traits/functions to a new module, without adding pub.

And using iterator methods directly on a collection, without .iter().

3 Likes

I'm not sure if it counts, but by far the most frequent mistake I make is for one hand to get ahead of the other while typing common words, resulting in things like uwnrap() or println(!"...").

rust-analyzer needs auto-correct :smile:

For some reason my brain stalls when it comes to using -> to introduce function return types and => in match expressions. So many times I have typed the wrong one.

Actually, is there any particular reason the same symbol cannot be used for both jobs?

3 Likes

Note that dbg!(x) returns x, so that you can insert it into the middle of an existing expression:

let w = foo(x, dbg!(y), z);
5 Likes

I know, but this can also create a problem:

foo(&dbg!(x)); // instead of foo(dbg!(&x))
bar(x);
1 Like

The one of these I do all the time is struct Foo { x: i32 }; after writing C(++) for a bit. But as you say, the error is good, so it's fine.

Similarly, I very often write if (blah) { ... } or while (whatever) { ... } after I've been doing C#. But that one's even less of an issue since it's just a warning about the parens.

This.

Now that even Sublime (which is more a text editor than a "real" IDE) has a button to apply structured suggestions, it's great being loose in what I write.

Once the signature is right, the compiler is amazingly good at nudging me in the right direction for the body.

2 Likes

I sometimes forget the :: from the turbofish syntax. I sometimes miss the ! for println!, for some odd-ball reason I still sometimes I type printf. I leave out the mut. I forget the .await. I often forget that certain uses of Command return two levels of error codes (one for launching, and one for the return value). I add semicolons where they shouldn't be, causing the Expected Blah, got () error. I sometimes mess up adding & and * where needed, even though I know perfectly well that they are needed. Another one of those left-overs from C is that I somewhat frequently switch type and variable name (fn foo(MyType: hello)) -- this happens in struct's as well.

I have noticed, by watching their streams, that the switching type and variable name around happens sometimes even among some pretty high profile Rust developers with plenty more years of Rust experience than I have.

Behold this massive can of worms: If we're all experiencing the same glitches in the matrix, is it a sign that there's a better way to do it? :grimacing: (I jest!)

2 Likes

Another thing I sometimes do is "shift key failure" when typing "'{" or "}" ( so get "[" or "]" instead ), the resulting error messages can be less than helpful, and it's not always easy to spot the mistake.

1 Like

I do sometimes forget the ! (but I don't support making ! optional).

I do sometimes forget the mut (and would be fine if it goes away for owned variables).

I mix up type and name order sometimes too, but prefer Rust's order. Though I sometimes pine for at least some generalized type ascription.

The "delete this semicolon" errors annoy me (and would like them to be allowed after a struct, say, but still not "transparent" at the end of a block where you're returning something).

I do this almost every time I have a trivial impl:

impl Trait for Struct;
//                   ^ should be {}

Which will probably be exacerbated if negative impls for all traits stabilizes. I wouldn't mind that one being allowed.

It took a really long time for "terminate declarative macro match arms with ;" to sink in (and I'm not sure why it is that way). Writing macros of any complexity is still mostly a "squint at errors and adjust until it works" exercise for me.

I'm long over it now, but there was a period where I would try to put the generic parameters of a function on fn instead of the name -- because a generic impl puts them on impl. Then somewhere I read "that's just because implementations don't have names to attach them to" and it cured me.

5 Likes

This. Debugging those tiny errors which make the whole block of code go red all of a sudden without almost any real suggestion as to what's causing the issue is extremely infuriating at times.

Forgetting the commas when defining struct-s is something I tend to forget most often.

1 Like

I almost consider the lack of auto-import in any code editor a bug rather than just a missing feature. Having to go to the top of the file and manually add an import is totally flow-breaking busywork.

1 Like

Someday I will be able to easily remember whether it's pub async fn or async pub fn. That day is not today :sweat_smile:

9 Likes

Not sure how common it is in general, but for me it is x: &'str every single time :weary:

4 Likes

After learning Swift, I keep writing if let foo = maybe_foo { ... }. I still can't decide if I like or dislike all the special sugar for Option in Swift..

Of course, like probably everyone else, missing semicolon at the end of a statement (may be Swift's fault as well) or comma at the end of a match arm is another frequent typo of mine.

I'm not sure this is silly, but missing Option::as_{de,}ref is quite frequent as well, since it's not needed in some cases because of match ergonomics but required in others.

I tend to group 'silly mistakes' into

  • 'don't care' because the IDE fixes it for me and
  • 'have to care' because the IDE doesn't fix it yet

For the latter, one that irritates me to no end is the following.

We are writing a function, so ends in
} // function
The last part of the function is a match, where we use the {}, so now it ends in

} // match, last clause
} // overall match
} // function

Now, in the last clause, we call an .map(), and the last part of the body is a func call, so now we have

) // func call inside map
} // ending closure body inside map
) // map call itself
} // match, last clause
} // overall match
} // function

And, if at any point during refactoring, we get a ')' or '}' mixed it, (putting the code in a broken unparsable state) it seems to confuse the auto indent system, so auto indent doesn't work, and then it's a manual process of matching up nested ({ with )} 's.

5 Likes