- Joined
- Jul 14, 2019
Disclaimer: I've written some decent-sized projects in Rust, and quite like the language to the point where I feel the need to defend it here.
Without realizing it, though, you've stumbled upon Rust's biggest flaw: most libraries are built on a mountain of macros and type system magic that makes them impossible to extend. Especially with "safe" wrappers around C libraries, like Rust-SDL2. I'd rather deal with the occasional unsafe function than that dumb shit.
In this line:
We create a
In order to use a trait's functions (
Had I written this example, I would have done something like this:
To explicitly emphasise the creation of the ThreadRng.
Pointers are scary things. A C function that takes a pointer as an argument can do anything with it - read from it, write to it, create infinite copies and propagate them to other objects or threads. Copies of a pointer can outlive the original data they were pointing to, causing memory corruption or even crashes if you try to write to the "dangling pointer".
Imagine you have a multiplayer game with
Or do you refrain from creating pointers to
With Rust, you can have your objects and eat them too, because there are rules in place to prevent dangling pointers and similar monstrosities:
I know that my autistic rant won't make the language any more appealing to you lot... I just wanted to point out that Rust has a method to its madness. It's a well-thought-out and meticulously designed language; most things that are hard to do in Rust are just transparent wrappers over things that are hard to do in general.
Surely it's better to determine conversion, string formatting, and typecasting at compile-time than at run-time?Apparently this is necessary because as you seeprintln!()
does both line-printing and string formatting, and Rust doesn't natively support variadic functions (functions with an arbitrary/undefined number of parameters), but they can be faked with macros. And rather than just having it be a function which takes a string and an array of strings to do the placeholder replacement with or some other sane alternative, they decided they'd implement it with macros and you can just litter your code with exclamation points and fuck off.
printf
alone has opened up a fuck ton of nasty security vulnerabilities.Without realizing it, though, you've stumbled upon Rust's biggest flaw: most libraries are built on a mountain of macros and type system magic that makes them impossible to extend. Especially with "safe" wrappers around C libraries, like Rust-SDL2. I'd rather deal with the occasional unsafe function than that dumb shit.
namespaces, libraries, and functions areNext, the intermingling of OOP-ish concepts with snake_case. We Ruby now bois. Speaking of which, I'm confused what significance the capitalization has in the namespacing.
snake_case
, types are PascalCase
.And why do weuse rand::Rng;
but then never actually use Rng anywhere?
Rng
is a trait, a collection of functions implemented by many different classes, akin to a Java interface or a Haskell typeclass. The Rng
trait covers functions common to all random number generators (thread RNGs, pseudo-RNGs, /dev/urandom/
, etc).In this line:
C-like:
let secret_number = rand::thread_rng().gen_range(1..101);
ThreadRng
with the constructor rand::thread_rng
, call its gen_range
function (which it implements as part of the Rng
trait) to get a random number, then silently discard it.In order to use a trait's functions (
gen_range
), you have to import the trait (Rng
) or the type that implements it (ThreadRng
). For some reason, this example doesn't explicitly import the ThreadRng
type, so it imports the Rng
trait instead.Had I written this example, I would have done something like this:
C-like:
use rand::rngs::ThreadRng;
fn main() {
// ...
// everything in rust is an expression
// every {} block can return a value
let secret_number = {
let rng : ThreadRng = rand::ThreadRng();
rng.gen_range(1..101)
};
//...
}
"Immutable" and "constant" are two different things. Constant values are determined at compile-time; Immutable values are determined at run-time, but not changed after that.let mut guess
. The "mut" keyword makes the variable mutable. I don't like the idea of immutable variables because we already have a word for those and it is "constant." JavaScript actually does something right by having separatelet
andconst
keywords for variables and constants rather than keyword-stacking.
This is quite literally the point of Rust.…Fuck me with a shovel. If you pass a variable by reference, it becomes a constant unless you add a keyword to make it otherwise. The fuck?
Pointers are scary things. A C function that takes a pointer as an argument can do anything with it - read from it, write to it, create infinite copies and propagate them to other objects or threads. Copies of a pointer can outlive the original data they were pointing to, causing memory corruption or even crashes if you try to write to the "dangling pointer".
Imagine you have a multiplayer game with
Player
objects dropping in and out of a server. How do you clean up after a player when they leave? Do you switch on a "dead" flag, allowing a dummy Player
to take up space in memory? Do you diligently search the game state for dangling pointers to the departing player?Or do you refrain from creating pointers to
Player
objects at all, instead referring to them by an ID? If that's the case, why bother having Player
objects at all? Why not just represent each player as a row in a database, indexing on the ID? This problem is a thorn in the side of any low-level language with an object system.With Rust, you can have your objects and eat them too, because there are rules in place to prevent dangling pointers and similar monstrosities:
- Pointers are explicitly specified as mutable or immutable
- Functions that take pointer arguments cannot propagate them outside of the function body
- Multiple mutable pointers to the same data cannot exist at the same time
- Data structures with pointers in them must be higher on the stack than whatever the pointer points to, unless a
Box,
Mutex
, or other smart pointer is used
I know that my autistic rant won't make the language any more appealing to you lot... I just wanted to point out that Rust has a method to its madness. It's a well-thought-out and meticulously designed language; most things that are hard to do in Rust are just transparent wrappers over things that are hard to do in general.
It's a brand name at this point. Rust has a reputation for spawning "X but better" projects (grep but better, GNU find but better, spotify but better). I've tried a few and confirmed that they are in fact better, though I'm hesitant to attribute this to the language itself.Rust aficionados seem to get a sexual thrill from rewriting perfectly-good software in Rust just so that they can say that they coded it in Rust.