Hacker News new | past | comments | ask | show | jobs | submit login
Can Rust prevent logic errors? (itsallaboutthebit.com)
24 points by drogus 10 months ago | hide | past | favorite | 5 comments



Rust absolutely can (and will!) prevent logic errors. Will it prevent all of them? Certainly not. But when I started using Rust there was a whole heap of "wait, did I ever even think about this class of error in any other peogramming language?" — and it turns out I did not.

The logic error prevention Rust has is purely done by the type system. E.g. when you read a file name this is a special kind of string (OsString), because some operating systems allow for combinations of bytes as filenames that are not valid unicode. Now if you want your regular Rust string, you have to do a conversion and that conversion will return a Result<String>, which means you either get an Ok<String> or an Error. If you don't handle that unpacking your program won't compile. Now you could just unwrap the result and live with a crash when there is an Error (and in some cases that would be totally valid), but you now know and have to decide how to handle it.

This for example would be something I didn't even know could be a problem and Rust made me handle it properly just be representing the thing in the type system. There are countless such things in the language.

Of couese if you go deeper, you have to represent your problems properly in the type system and there you can certainly introduce mistakes.


This isn't really specific to Rust's type system, though. It's more related to the philosophy of the language and how the standard library is implemented. You could have the same behaviour in most other traditional programming languages.

Though, Rust's type system and syntactical features probably lend themselves to more ergonomic handling of the various error states.


This kind of type system capability is available in most languages of Standard ML linage, although many associate it with Rust only.


The relevant maxim comes from John Ousterhout's A Philosophy of Software Design, specifically Chapter 10, "The best way to eliminate exception handling complexity is to define your APIs so that there are no exceptions to handle: define errors out of existence".

This approach isn't unique to Rust, though I applaud Piotr Sarnacki for going into detail about how to approach the concept. The undercurrent of design this article suggests is to avoid primitive obsession, and define appropriately constrained types. In the example of concurrency, the HashMap type is, outside of the owner, immutable, unless ownership and mutability becomes part of the type definition.

Too often programmers use String or Integer when they really should be using a domain-relevant type (which might be implemented under the covers with a primitive) enforcing the bounds. For example, using an integer for the Natural Numbers opens up all kinds of issues. Even using unsigned int is wrong, because subtracting a larger number from a smaller number because subtraction of natural numbers is not closed.


Rust has features that look like equivalents of footguns in other languages, so it's easy to assume it can have the same failures.

For example, Rust has Option<String> that is a "nullable" string. missing.unwrap() will throw an exception or abort the program, just like a null pointer access would. You could think that a "bad programmer" will find these footguns and write just as bad code. But subtle differences in how these features work make a big difference in real-world use, even in the hands of careless programmers. A change between non-optional and optional is a type error that needs to be fixed everywhere. Option requires answering "what if it's empty" on every use, so a properly lazy programmer will avoid making things optional in the first place.

Rust also has good defaults. A struct type by default can't be copied, can't be compared, can't be serialized, can't be printed, can't be implicitly created from default values. The programmer is forced to think and explicitly write what can be done with the type. So users of a type can't carelessly copy a unique handle, or end up comparing addresses when they mean to compare values, even if the programmer writing the type forgot to consider these issues.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: