Learning Rust by Contrasting with TypeScript: Part 6
By: John Tucker
Tags: Web Development, Typescript, Rust

Exploring the unexpected power of enums.

This article is part of a series starting with Learning Rust by Contrasting with TypeScript: Part 1.

The examples from this article are available for download: Rust download and TypeScript download.

Let us walk through the examples in the Rust Book Enums and Pattern Matching section and contrast them with TypeScript.

Enums

Strangely enough, I found enums a bit more challenging to understand than the previous material; found the idea of associating data with the enum variant hard to get my head around.

It wasn’t until the documentation described that the following enum…

enum Message {

Quit,

Move { x: i32, y: i32 },

Write(String),

ChangeColor(i32, i32, i32),

}

…could be described as a list of struct-like structures.

Defining an enum with variants such as the ones in Listing 6–2 is similar to defining different kinds of struct definitions, except the enum doesn’t use the struct keyword and all the variants are grouped together under the Message type. The following structs could hold the same data that the preceding enum variants hold:

— Rust Team — Defining an Enum

struct QuitMessage; // unit struct

struct MoveMessage {

x: i32,

y: i32,

}

struct WriteMessage(String); // tuple struct

struct ChangeColorMessage(i32, i32, i32); // tuple struct

With this in mind, we can then can make sense of enums and explore all their features:

Observations:

When I first wrote this example, I was surprised to see that a variable that contained an enum, e.g., coin, did not support the Copy trait. It turns out that assigning coin to coin2 is a move operation. This is completely understandable if one thinks of an enum variant as a struct-like structure

The second match coin3 and the if let statements are equivalent. As a matter of fact, this is the only way I could understand what if let is

While TypeScript has enums, they (for the most part) as just a convenient way to name numbers, e.g., 0, 1, 2, etc. We can mostly approximate our previous example by using a combination of an enum and a class.

Observations:

This approach requires that each instance have the same associated data structure (in this case the number value). Notice we had to use a null to represent a unused value

Unlike Rusts match statement, the switch statement does not ensure we exhaust the enum’s variants

Option Enum

In writing this article, I have come to better appreciate the following observation.

The problem with null values is that if you try to use a null value as a not-null value, you’ll get an error of some kind. Because this null or not-null property is pervasive, it’s extremely easy to make this kind of error.

— The Rust Team — Defining an Enum

And come to appreciate the simplicity and power of Rust enums. Find it a bit mind-boggling that the introduction of the built-in Option enum solves the null problem.

enum Option<T> {

Some(T),

None,

}

Here is a simple example of using the Option enum:

Here is the TypeScript version of the same idea:

Observation:

First observation is that neither TypeScript or strict linting (added ESLint to this example) enforced the null check in either the plusOne or len functions

In the case of the plusOne function, omitting the null check caused a null parameter to be treated as 0 and thus the function would return 1

In the case of the len function, omitting the null check caused a run-time error when passed a null parameter

Next Steps

We explore Rust’s module system in Learning Rust by Contrasting with TypeScript: Part 7.