Comparing Traits in Rust to Type Classes in Scala

Fehmi Can Saglam
3 min readJan 4, 2022

I have been reading The Rust Programming Language and Scala with Cats simultaneously for the last couple of weeks to refresh my memory in both topics. While reading about Traits in “the Rust book” I noticed how similar Rust’s Traits and Scala’s Type Classes are. Let me walk you through the example in the Rust book and translate the code into Scala.

Update: I have added Scala 3 code samples to the very bottom of the article.

It all starts with defining a common “summarize” behavior in a trait that will allow us to get summaries for different types such as tweets or articles. Here is the Rust version of the aforementioned trait:

pub trait Summary {     
fn summarize(&self) -> String;
}

And this is how you define the same trait in Scala:

trait Summary[A] {
def summarize(a: A): String
}

Then the Rust book defines two structs implementing the Summary trait. I must admit that it’s quite straightforward in Rust to define your value classes and provide trait implementations for them.

pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}

This becomes a bit more messy in Scala. Instead of structs we use case classes which is still very straightforward and clean. But I’d say providing implicit type class instances for concrete types is tedious.

case class NewsArticle(
headline: String,
location: String,
author: String,
content: String
)
object NewsArticle {
implicit val newsArticleSummary = new Summary[NewsArticle] {
override def summarize(newsArticle: NewsArticle): String = {
import newsArticle._
s"$headline, by $author ($location)"
}
}
}
case class Tweet(
username: String,
content: String,
reply: Boolean,
retweet: Boolean
)
object Tweet {
implicit val tweetSummary = new Summary[Tweet] {
override def summarize(tweet: Tweet): String = {
import tweet._
s"$username: $content"
}
}
}

Now it’s time to use the behavior we have implemented. In Rust you simply create a tweet instance (or another type that implements Summary) and call .summarize() on that instance. It’s nice, isn’t it?

let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());

Achieving the same thing in Scala is a bit tricky. We need to define an extension method using an implicit class. This is generally referred to as syntax.

object SummarySyntax {
implicit class SummaryOps[A](val a: A) extends AnyVal {
def summarize()(implicit summary: Summary[A]): String = {
summary.summarize(a)
}
}
}

Then it again becomes quite similar. We create the tweet instance and call .summarize() on it.

val tweet = Tweet(
username = "horse_ebooks",
content = "of course, as you probably already know, people",
reply = false,
retweet = false
)
import SummarySyntax._println(s"1 new tweet: ${tweet.summarize()}")

Lastly I’d like to mention traits as function parameters and how they are almost the same in both languages. This is how you define a function that accepts a parameter implementing the Summary trait in Rust:

pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}

And this is the Scala translation:

def notify[A: Summary](item: A) {
println(s"Breaking news! ${item.summarize()}");
}

Type Classes in Scala 3

It’s much more straightforward in Scala 3 (compared to Scala 2) to implement type classes. Let’s create the Summary type class first:

trait Summary[A] {
extension(a: A) def summarize: String
}

After that we just need to implement concrete instances:

given Summary[NewsArticle] with
extension(newsArticle: NewsArticle)
def summarize: String =
import newsArticle._
s"$headline, by $author ($location)"
given Summary[Tweet] with
extension(tweet: Tweet)
def summarize: String =
import tweet._
s"$username: $content"

At this point we can directly call .summarize on a type that implements the Summary type class.

val tweet = Tweet(
username = "horse_ebooks",
content = "of course, as you probably already know, people",
reply = false,
retweet = false
)
println(s"1 new tweet: ${tweet.summarize}")

I hope you enjoyed the similarities between Rust and Scala like me. I have a superpeer profile. Please feel free to book a 30 min session if you would like to talk more about Rust, Scala and software development in general. Use code RUST(valid until 2022–02–28) for a 40% discount. I’m also on Twitter.

--

--

Fehmi Can Saglam

I’m a software engineer based in Berlin. I write mostly about programming and living healthy.