As you might have noticed, Go seems to be quite the star right now. Strangely enough, I just started with it right before I suddenly heard it everywhere.
And I mean, it's a fantastic language. It was, in fact, my favorite language. Still is one of the top ones. I made a pretty huge application in it actually, which has gotten a lot of love for being from me (I'm pretty damn unknown to be honest).
So Rust then, what is it? Why am I talking about it now? Right from the start actually, my buddy @tbodt seemed fashinated about the language. None of us ever dugged very deep into it, as far as I know. I was busy with Go, pretty much.
Anyways, since I'm not professionally schooled and only a little teen hobbyist, I only just heard about data races. Of course, I hurried to update most of my applications. Including my biggest one. (All goes fine until I suddenly seem to get a goroutine leak for no apparent reason thanks to the new mutexes I put in place.)
Then I was a little bored, I looked into Rust.
My other buddy @nstafie, who I knew from the discordgo community, talked highly about it.
That's when I got into it.
Deciding to actually make a test project, I read the initial tutorial and learned as much as I could and made the tiniest test ideas I could think of.
Go vs Rust????
Remember my good ol' program that is a little buggy? I got the idea of rewriting it in Rust. Of course, I definitely wouldn't want to do that huge thing, but... yeah it was a nice thought.
Until one day, I get convinced by the discordgo community to rewrite my a little crappy code. So would I do it in Go?
Rust.
I chose Rust because it has a few tricks up it's sleeve compared to Go.
- Macros. They are probably the most underrated things I've ever seen in programming. Ever wished you were able to return a function from a function? Well, macros can do just that. Plus they trade space for speed. But let's be honest, people have infinite hard drives now-a-days. Still, be careful.
- Generics. This might not be something I use myself, but because of generics, it's possible for the standard library to add slightly higher functions like contains and amazing stuff.
- Control. Barely any type implements the
Copy
"trait" (a.k.a. Rust'sinterface
). While this makes you pull your hair out, it also makes you aware of when copies are needed, and you can see if you can avoid them. And even if you can't, which is most of the time, you can just add.clone()
.
But that wasn't the biggest reason
Compile time errors and warnings
One of the really cool things I saw when using Rust, was when I did something pretty stupid and compared if user input stored in an unsigned int was < 0
. Guess what? Rust warned me about useless check!!
One of the best advantages with compiled languages over just-in-time compiled or interpreted ones, just got a million times better. In fact, during my whole rewrite, I haven't gotten a runtime panic one single time until today (when I tried to use a function result in a macro directly... oops)
This goes to show that you suffer for your users.
Of course, I still barely understand the error messages. While they attempt to be helpful, they are still a little big and bulky, and not always really very accurate to what you want.
Go and Rust????
Don't tell me I've switched to Rust. While we both know that's true, I like to see myself as somebody who would not be afraid of switching languages per project.
Go is definitely a cool language, and is still great for a lot of things.
- Go is definitely easier to understand.
- Go has a lot of things built in, which Rust doesn't. The biggest missing built-in is signal handling but other missing built-ins include lazy static, http support and parsing command line arguments and JSON.
But I loved Go. What could Rust possibly have done that could make me swi-
I didn't.
You might not see it, but Rust and Go are amazingly similar compared to other languages.
- Understandable type naming. Seriously, I didn't know what the difference between
float
anddouble
was until Go and Rust came around and said it'sf32
/float32
andf64
/float64
(where the latter is Go.) - Type AFTER the name. Not the biggest deal, but it would make sense figuring out what type a variable is after figuring out which variable.
- Return type last. Same as above.
Conclusion.
Sorry for making you read so much. Jeez!
In short, Rust is C + Go + convenience + (annoyance * 10)
.
Definitely useful for anything, but not always the right language of choice.
The rewrite I were talking about can be see here
Have fun!
Top comments (11)
You can do some pretty nifty stuff with generics. For example, they're one of the ways you can implement what are called "session types", which can be used to verify, at compile time, that your use of a finite state machine is valid.
(Basically, you implement a type with a generic parameter representing the state, then only "impl" functions on the states where they make sense. Rust's ownership system then ensures that you can't keep and use a reference to an old state once you've transitioned to a new one.)
Hyper uses them to implement an HTTP request type where it's a compile-time error to add a header after the body has already started streaming.
Another trick you can do is stuff like
Temperature<T>
, where operators like+
are only defined for cases where the twoT
parameters match, socelsius + fahrenheit
is a compile-time error. (Stylo uses this sort of trick to catch things like trying to add lengths of different units without first converting them to match.)If you like that, check out the lints offered by Clippy.
Just be aware that, because of how deeply it hooks into the compiler, you'll need to use
rustup toolchain install
to install a nightly version of the compiler,cargo +nightly install clippy
to install clippy, andcargo +nightly clippy
to run it on your code.(Last I heard, the end goal is to distribute it via rustup, same as the compiler, so it can use the "allow unstable interfaces in stable builds" trick used to compile the standard library.)
If you're on Linux, I've got all of the setup and dispatch automated (and well-documented) using just in my CLI utility project template.
The difference is that Rust has a much more advanced dependency management story than Go. (In fact, it's the best I've used in any language)
Because of that, Rust erred more on the side of learning from the Python community's statement that "things in the standard library have one foot in the grave".
(If it's part of the standard library, the only way to offer 1.x in maintenance mode and 2.x to fix design flaws is to put two copies with different names in the standard library for all eternity.)
You seem to be undervaluing Rust's type system. Generics aside, one of the biggest complaints I see Rust users having when they try Go is how there's no middle-ground between using exact types and using
interface{}
.In Rust, you've got much more of a middle-ground to specify what is valid and invalid in terms the compiler can verify before you ever run your program. See, for example, Writing Idiomatic Libraries in Rust by Pascal Hertleif (28 minutes).
Go has interfaces beyond
interface{}
, and you should use them exactly for that. They allow you to refer to things based on what functions they provide instead of what someone wrote in aninherits
or similar.Good point. That was a big phrasing mistake on my part. A better expression of what I was thinking would be "insufficient middle-ground".
I'm sure at least some of it is that we've been spoiled by Rust's excellent support for using sum types (enums containing data... A.K.A. compiler-verified tagged unions) to extend the compiler's ability to catch mistakes in variably-typed fields.
(The name "sum type" refers to the set of possible combinations. A tagged union is the sum of the possible combinations of its values. A struct is an example of a product type because its possible combinations are the set product of the possible combinations of its members.)
...but then the Rust community are overachievers that way. They've been working hard to design a viable system of Pi/Dependent types. (Types where, as in Ada, you can say that type
Rating
is "Typeu8
where the value is in the range '1
through5
'" and get various kinds of compile-time goodness from it.)Whoop, thanks for your comment!
already running it when I remember to :)
Yup! Forgot to mention anything about generics or "you pay for what you use" in that equation.
C does that too
You mean GCC? Or which compiler? Anyways, sounds good!
any compiler that supports -Wall
You can do that in Go as well and in any other language that implements "higher order functions". You don't need macros for that, they serve a different purpose for more advanced tasks.
Oh so that's Rust! I think I got quite the good impression from this, thumbs up. (-:
Thanks =)
Indicates a fundamental misunderstanding of what "trade space for speed" actually means.