ProgrammingBackend Developer

How are type aliases implemented in Rust, how do they differ from newtypes, and why is it important to understand the difference when designing APIs?

Pass interviews with Hintsage AI assistant

Answer.

In Rust, you can use the type keyword to create an alias for an existing type. For example:

type Kilometers = i32; fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { x + y }

Kilometers is just another name for i32; the compiler does not differentiate between these types, and they are completely interchangeable.

Newtype pattern is creating a new wrapper structure for an existing type:

struct Kilometers(i32); // a separate new type fn add_distance(x: Kilometers, y: Kilometers) -> Kilometers { Kilometers(x.0 + y.0) }

Now Kilometers and i32 are different types, and they cannot be confused.

  • Aliases are convenient for readability or generalized APIs.
  • Newtype pattern provides type safety and allows implementing unique traits for new types.

The choice between these approaches depends on safety and readability requirements. For public APIs and especially type-safe units of measurement, use newtype.

Tricky question.

What is the difference between type alias and newtype pattern in Rust? Can you limit operations for a type alias through trait implementation?

It is often answered that an alias can be used for access control and limiting operations, but that's not true — an alias does not create a new type, and thus unique traits cannot be implemented for it. Only the newtype pattern is a separate type, for which unique behavior can be implemented.

type UserId = u64; struct UserIdNew(u64); trait Foo { fn foo(&self); } // Implementing Foo for UserId is not possible because it's just u64. // For UserIdNew — it is possible.

Examples of real errors due to lack of knowledge on the topic.


Story

In the project, distances were measured in meters and millimeters using aliases:

type Millimeters = u32; type Meters = u32;

In the final code, millimeters were accidentally added to meters, leading to calculation errors. The typing didn't catch this — the compiler didn't catch it at all. Switching to newtype resolved the issue.


Story

In a public API, aliases were used for identifiers of different entities (type UserId = u64;, type OrderId = u64;). Confusion arose: someone mixed up the parameters, and a bug went into production due to the inability to distinguish them by types.


Story

A developer attempted to implement unique behavior for the Display trait for a type alias:

type MyType = String; impl Display for MyType { ... }

The compiler raised an error: "cannot implement trait for type alias". The problem was resolved through the newtype pattern.