DEV Community

Discussion on: Benefits of Rust

Collapse
 
ssokolow profile image
Stephan Sokolow • Edited

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.

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 two T parameters match, so celsius + 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.)

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!!

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, and cargo +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.

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.

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.)

In short, Rust is C + Go + convenience + (annoyance * 10).

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).

Collapse
 
legolord208 profile image
jD91mZM2

Whoop, thanks for your comment!

If you like that, check out the lints offered by Clippy.

already running it when I remember to :)

You seem to be undervaluing Rust's type system

Yup! Forgot to mention anything about generics or "you pay for what you use" in that equation.

Collapse
 
erebos-manannan profile image
Erebos Manannán

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{}.

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 an inherits or similar.

package main

import "fmt"

type Fooer interface {
    foo()
}

type Bar struct {
}

func (b Bar) foo() {
    fmt.Println("foo")
}

func useFooer(f Fooer) {
    f.foo()
}

func main() {
    useFooer(Bar{})
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ssokolow profile image
Stephan Sokolow • Edited

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 "Type u8 where the value is in the range '1 through 5'" and get various kinds of compile-time goodness from it.)