Dart 3: Switch and Records in tandem

Dart 3: Switch and Records in tandem

Combine switch expressions with the new record feature

Dart 3 was introduced a few months ago and brought a lot of interesting changes. Among those new features were the "Record" type and more powerful switch expressions. This article will focus on the combination of these two features.
Before diving deep into our main subject, let's take a look at a few key points concerning these two features.

Switch expressions

So as not to go into too much detail, let's talk about things that may be confusing with the new switch expressions.

The thing you have to keep in mind is that in Dart 3, switch expressions can be used as a return value or as a conditional expression, and the syntax is a bit different for each case.

  1. Usage as a conditional expression

Let's consider this code block; we want to print a particular message for each user type.

Nothing different from the usual, here.

  1. Usage as a return value

However, if we want to refactor this code to return a message by user type, the syntax might change just a little.

The main differences here are:

  • The absence of the "case" keyword

  • The two dots after the enum case are replaced by an arrow

  • Semicolons after each case are replaced by a comma

  • Usage of an underscore instead of the default keyword

Records

If you don't know what it is, I recommend you read this article, which discusses it in detail: Dart 3 in depth: Records

Let's combine both

Now we have a better understanding of both features. Let's see how we can combine them to give superpowers to our control structures while maintaining an acceptable level of legibility.

Let's take a simple example. We want to execute some operations depending on the state of three booleans:

  1. We want to show the paywall to a user depending on some conditions:
  • The user should be logged in

  • The user should not have an active subscription

  • The paywall should have been showed more than 6 days ago

  1. If the user is not logged in, we want to show them a notice to tell them their work can be lost

  2. If the user is a pro member, we want to show them an in-app review/system

This example is deliberately simple to facilitate understanding of our subject.

Let's say we want to implement these checks. We would then have a piece of code that looked like this:

Adding a condition to this code would make it a little denser and therefore affect its readability. It would be very easy to get lost, both during implementation and reading.

Now let's see how we can "simplify" this code by combining records and a switch:

What's happening here:

  • We are going through all our covered cases in a much cleaner way*

  • Each case is treated directly with its values; for example, if you want to display a paywall, it is easier to understand which combinations of values you want to perform a given treatment.

  • "Any" values are treated with an underscore. "any value" here is used to represent values that don't affect the condition; we don't care what their value is as long as the others have the expected value.

*much cleaner way: This argument is debatable and ultimately depends on the developer. My opinion may not be the same as yours.

Although this approach may be more verbose than the "classic" approach for large conditions, it offers a real advantage in terms of readability - a readability that could be improved by using named records.

I personally use this pattern a lot. The only "drawback" (if it really is one) that I've noticed so far is that you have to respect the order of the conditions (even more vigilance when you have "any" values in the conditions) to avoid misbehaving.

Did you find this article valuable?

Support Steve Nosse by becoming a sponsor. Any amount is appreciated!