Hey all, just a cautionary note of advice when wor...
# daft-dev
r
Hey all, just a cautionary note of advice when working with enums in Rust. I see a lot of the following:
Copy code
enum MyEnum {
  Variant1,
  Variant2,
}

use MyEnum::*;
match my_enum {
  Variant1 => ...,
  Variant2 => ...,
}
The problem here is with the
use MyEnum::*;
. Although it is more concise, this can lead to a whole suite of nasty issues further down the line. The specific problem is that
Variant1
and
Variant2
will work here. But imagine if we change the definition of
MyEnum
to be:
Copy code
enum MyEnum {
  Variant1,
  NewVariant2,
}
If we make the above change, the following code will still continue to compile successfully:
Copy code
use MyEnum::*;
match my_enum {
  Variant1 => ...,
  Variant2 => ...,
}
The reason being is that the left hand side of the match-arrow is a pattern-matching construct. Pattern matches can either be the name of one of the enum's variants OR, if the enum does not have that name, it can be treated as an identifier. Therefore, after our change to the definition of
MyEnum
,
Variant2 => ...
will instead be treated as a variable binding! More specifically,
Variant2
will now bind to
MyEnum::NewVariant2
. This can become even more ugly when we further modify our definition of
MyEnum
. For example, consider this new definition:
Copy code
enum MyEnum {
  Variant1,
  NewVariant2,
  MyNewSuperCoolVariant3,
}
and consider our still unmodified original match condition:
Copy code
use MyEnum::*;
match my_enum {
  Variant1 => ...,
  Variant2 => ...,
}
Here,
Variant2
will be treated as a variable binding and will bind to
MyEnum::NewVariant2
and
MyEnum::MyNewSuperCoolVariant3
!!! This can lead to a whole host of ugly problems down the road and creates a whole bunch of technical debt. The only sign that
rustc
will give to you when compiling that program is a casing-warning. Specifically, it'll say something like "You are using CamelCase for this variable (Variant2), but instead you should be using snake_case (variant_2)". This is just a warning! We've made breaking changes to our definition of
MyEnum
, and the only sign that we get from
rustc
is a silly little case-warning! This defeats the entire purpose of using a good algebraic type system that Rust gives us. Please resort to using the full, qualified variant names of enums! Something like:
Copy code
match my_enum {
  MyEnum::Variant1 => ...,
  MyEnum::NewVariant2 => ...,
  MyEnum::MyNewSuperCoolVariant3 => ...,
}
I know it's more verbose, but it will save us a LOT of headaches down the line in the future! Thanks in advance!
pikachu shocked 1
❤️ 3
I have a side PR that I created this week that incrementally changes some of these instances I've seen. I definitely won't have a big, large, singular PR that updates all of this at once, since that'll be way too big, but I'm planning on making these changes and merging them in in small, bite-sized increments as time goes on!
d
TIL, thanks for sharing! Somewhat relatedly, I think we should also namespace non-locally defined functions. The relevant part of the rust book says
Bringing the function’s parent module into scope with use means we have to specify the parent module when calling the function. Specifying the parent module when calling the function makes it clear that the function isn’t locally defined while still minimizing repetition of the full path. The code in Listing 7-13 is unclear as to where add_to_waitlist is defined.
On the other hand, when bringing in structs, enums, and other items with use, it’s idiomatic to specify the full path.
❤️ 1
r
That also seems like a fantastic piece of advice. Something that I should probably integrate into my habits as well. Seems like it would be a great way to mentally keep a tab of where things are located, to help with comprehension of our codebase. I'm of the opinion that a few extra keystrokes won't harm anyone, and rather go a long way in helping maintain readability and code-comprehension, especially for a project that many people are working on!
plus one 1
The open source
buck2
build tool (written in Rust and developed at Meta) actually has a really cool styling guideline for new contributors. Things such as what Desmond and I mentioned in this thread. Daft could also have something similar!
(Link to the above file, for those that are curious: https://github.com/facebook/buck2/blob/main/HACKING.md)