What are some mind blowing Rust tricks?
What are some mind blowing Rust tricks?
If we were to create a Rust version of this page for Haskell, what cool programming techniques would you add to it?
What are some mind blowing Rust tricks?
If we were to create a Rust version of this page for Haskell, what cool programming techniques would you add to it?
Not exactly the same thing but this is still pretty funny. This is code that is technically 100% legal Rust but you should definitely never write such code 😅.
That makes complete sense. Ranges implement fmt::Debug
, ..
is a range, in particular the full range (all values) ..=
isn't because the upper bound is missing but ..=..
ranges from the beginning to the... full range. Which doesn't make sense semantically but you can debug print it so add a couple more nested calls and you get a punch card.
I totally didn't need the Rust playground to figure that out.
EDIT: Oh, glossed over that: ..
is only the full range if standing alone, it's also an infix operator which is why you can add as many as you want (be careful with whitespace, though). .. .. .. .. .. .. .. .. .. ..
is a valid Rust expression.
This is excellent content
A cool thing you can do, is to store values of all kinds of types in a big HashMap, basically by storing their TypeId
and casting them to Box<dyn Any>
(see std::any).
Then you can later retrieve those values by specifying the type (and optionally another ID for storing multiple values of the same type).
So, you can create an API which is used like this:
rust
let value = MyType::new(); storage.insert(value); let retrieved = storage.get::<MyType>(); assert_eq!(retrieved, value);
There's various ECS storage libraries which also implement such an API. Depending on what you're doing, you might prefer to use those rather than implementing it yourself, but it's not too difficult to implement yourself.
There's a crate for it too: anymap2
What if I specify the wrong type? let retrieved = storage.get::<SomeOtherType>();
?
Is it a runtime error or a compile time error?
To answer my own question: I believe it's a runtime error: https://doc.rust-lang.org/stable/std/any/trait.Any.html#method.downcast
Rust isn't really a language that lends itself to terse point-free functional idioms... The sort of examples I might want to share would probably require a bit more context, certainly more code. Like I think type guards and arena allocation are cool and useful tricks but I don't think I could write a neat little example showing or motivating either
Something i didnt know for a long time (even though its mentioned in the book pretty sure) is that enum discriminants work like functions
rust
#[derive(Debug, PartialEq, Eq)] enum Foo { Bar(i32), } let x: Vec<_> = [1, 2, 3] .into_iter() .map(Foo::Bar) .collect(); assert_eq!( x, vec![Foo::Bar(1), Foo::Bar(2), Foo::Bar(3)] );
Not too crazy but its something that blew my mind when i first saw it
This works with anything that one might call "named tuples".
So, you can also define a struct like so and it'll work:
rust
struct Baz(i32);
On the other hand, if you define an enum variant with the normal struct syntax, it does not work:
rust
enum Foo { ... Qux { something: i32 } //cannot omit braces }
Named function arguments would occasionally be nice to have instead of the single n-tuple they take now. Currently I'm more or less playing a game of "can I name my local variables such that rust-analyzer won't display the argument name when I stick them into functions (because they're called the same)).
Clippy will warn you if you don't use this feature.
Yea it's like when we writeSome(2)
. It's not a function call but a variant of the Option
enum.
One thing I like a lot about Rust is that it rarely does blow my mind.
But one crate that actually did blow my mind is corosensei. It's not Rust per se that is so crazy here, but the way it's essentially implementing a new language feature with assembly code. This is how you know Rust really is a systems programming language. I invite you to read the source code.
Oh wow I've been looking for something nice like that for ages. Python can do this and it's really great for silicon verification test stimulus. I've also done it in C++ using C++20 coroutines, but they are so complicated and low level I ended up having to use a library to help (libcoro). Felt like a bit of a gap in Rust, but this looks like a great solution!
Mindblowing features are basically, by definition, a result of bad language design. They blow your mind, since they are totally unexpected behaviours. They may still be cool, but they are unexpected and hence unintuitive.
A language that are full of these is Perl. And one simple one is that you can take the string "AAAAA" and use addition on that, like "AAAAA"++ and you will get the result "AAAAB". Cool you may think, but is it really? Addition is normally used to increase the value of a number, that is a completely different operation than modifying a String. The string "AAAAA" cannot be said to be greater or less than "AAAAB", besides the very special case when we order it. But in general the name "John" is not considered to be higher/lower than "Mark", they are just different. So, even if it is cool to manipulate strings by using addition/subtraction, it is still bad language design and very unintuitive. Also, since perl is so loosely typed, it may also cause very unexpected bugs.
The general theme of your comment is good, but the example is...
The string “AAAAA” cannot be said to be greater or less than “AAAAB”
But in general the name “John” is not considered to be higher/lower than “Mark”
rust
// rust eprintln!("{}", "AAAAB" > "AAAAA") // true eprintln!("{}", "Mark" > "John") // true
c
// C printf("%d\n", strcmp("AAAAB", "AAAAA")); // 1 printf("%d\n", strcmp("Mark", "John")); // 1
strcmp()
docs:
strcmp() returns an integer indicating the result of the comparison, as follows:
- 0, if the s1 and s2 are equal;
- a negative value if s1 is less than s2;
- a positive value if s1 is greater than s2.
So basically, if C had higher level constructs, it would be identical to Rust here.
So, even if it is cool to manipulate strings by using addition/subtraction, it is still bad language design and very unintuitive.
Rust has impl Add<&str> for String
and impl AddAssign<&str> for String
. Both append as expected.
But maybe you meant numeric addition specifically.
In that case, yes, Rust doesn't have that, although it's an impl<'a> Step for &'a str
away from having something similar (it would be ("AAAAA"..).next()
).
impl Step for char
already exists of course, but shouldn't if we take your argument to its logical conclusion.
Oh, and C would most definitely have this feature if it could. Numerical manipulation of char
s is commonplace there.
Rust has impl Add<&str> for String and impl AddAssign<&str> for String. Both append as expected.
I wouldn't go so far and say "as expected": "Addition" implies that we're dealing with a ring, that there's also multiplication, and that really doesn't make sense for strings (unless you indeed consider them numbers). It's why Haskell's Monoid
typeclass comes with the function mappend
, not madd
.
In Rust's defence though std::ops
traits aren't meant to carry any semantics they're about syntax: It's called Add
because it's +
, not because it means something. I do think it would've been worth it to introduce ++
for general appending (also vectors, sets, maps, etc), though, to keep things clean. Also ++=
for the mutating case.
The string “AAAAA” cannot be said to be greater or less than “AAAAB”, besides the very special case when we order it.
I hate it to break it to you but it's the same with numbers.
Ok, I then have some business proposals....
I'd like to see a Rust solution to Tony Morris's tic tac toe challenge:
https://blog.tmorris.net/posts/scala-exercise-with-types-and-abstraction/index.html
His rant about it is here:
I did a Haskell GADT solution some time back and it's supposed to be doable in Java and in C++. Probably Rust too. I wonder about Ada.
This could be done almost trivially using the typestate pattern: https://zerotomastery.io/blog/rust-typestate-patterns/.
Neat that looks interesting. There's a similar Haskell idiom called session types. I have a bit of reservation about whether one can easily use Rust traits to mark out the permissible state sets that an operation can take, but that's because I don't know Rust at all. I do remember doing a hacky thing with TypeLits in Haskell to handle that. Basically you can have numbers in the type signatures and do some limited arithmetic with them at type level. I'd be interested to know if that is doable in Rust.
That doesn't look like a particularly difficult challenge? Like, it's just an implementation game, move returns a data type that you write yourself
Edit: I suppose there's life in that kind of ambiguous variation though
Well if there isn't already a Rust version on github, it could be cool to add one. A few other languages are already there.
You can manually implement PartialEq and Eq on an Enum that implements Hash to manually determine how the hashmap keys override/collide with one another.
Here's another Haskell example where I'd be interested to see a Rust counterpart. It's a red-black tree implementation where the tree invariants are enforced by types. The code would less ugly with more recent GHC features, but same idea.
The haskell examples look more like an arcane wizardry.
My favorite example of haskell arcane wizardry is löb. It's mentioned in this list but not really done justice imo.
😂 Ikr!
Can't think of anything.
The novelty must have worn off over time.
Or maybe my mind doesn't get blown easily.