Understanding the Benefits of Rust's Type System in the Newtype Pattern

Hey there!
I recently started learning Rust and am currently digging into some common patterns, currently the Newtype pattern.
I've read that Rust has a much stronger type system than other languages, but I currently don't quite understand the practical benefits in some situations.

Say we have a struct User:

struct User {
  name: String,
  password: String,
}

If I wanted to differentiate the fields and give the password some special behavior, I could refactor it like this:

pub struct Password(String);
// impl goes here...

This makes sense to me conceptually, however I don't quite get the benefit the type system is giving me here, compared to some language like Java where I could do something such as this:

public class User {
  private String name;
  private Password password;

  public User(String name, String password) {
      this.name = name;
      this.password = new Password(password); 
    }
}

public class Password {
  private String value;

  public Password(String value) {
    this.value = value;
  }

  // methods go here
}

In both cases, I can encapsulate special behavior for Password. What specific advantages does the Rust type system give me here that a language like Java wouldn’t?
Thanks in advance! :slight_smile:

Don't get me wrong, but I think you are not seeing any advantages precisely because you are only looking at the newtype pattern. It's like saying that Haskell doesn't provide any advantages over Java since both have a type for strings.

What sets Rust's type system apart is, when compared to Java's for example, that it can prevent data races, it provides null-safety, and in general that you can model more constraints and more easily.

2 Likes

The idea is that the constructor of User should take a Password not a String, so the caller can't confuse the two.

Also, what's different from Java is that doing this is zero-cost, while in Java you would end up with one more heap allocated object, double indirection, etc. This means in Rust you can use this pattern wherever you like, without worrying about performance drawbacks.

9 Likes