From F# to Scala – traits

You can become a serverless blackbelt. Enrol to my 4-week online workshop Production-Ready Serverless and gain hands-on experience building something from scratch using serverless technologies. At the end of the workshop, you should have a broader view of the challenges you will face as your serverless architecture matures and expands. You should also have a firm grasp on when serverless is a good fit for your system as well as common pitfalls you need to avoid. Sign up now and get 15% discount with the code yanprs15!

Read the whole series:

Part 1 — type inference

Part 2 — traits <- you’re here

Part 3 — case class/object (ADTs)

Part 4 — apply & unapply functions

Part 5 — implicits

Continuing on from where we left off with type inference last time around, let’s look at a language feature in Scala that doesn’t exist in F# – traits.

Scala has both abstract classes and traits (think of them as interfaces, but we’ll get into the differences shortly) to support OOP. Abstract classes are exactly what you’d expect and the preferred option where Java-interop is concerned. Traits, however, are much more flexible and powerful, but with great power comes great responsibility.



Like abstract classes, they can contain both fields and behaviour, and both abstract definitions and concrete implementations.

Any class that extends from this trait will inherit all the concrete implementations and need to implement the abstract members.

Of course, the concrete class can also override the default implementation that came with the trait.

You can extend multiple traits.

wait, hold on a sec, what’s this object thingymajig?

Sorry for springing that on you! A Scala object is basically a singleton and is Scala’s equivalent to a F# module. In fact, when you define an object in the Scala REPL it actually says “defined module“!

The notable difference with a F# module is that a Scala object can extend abstract classes and/or traits (but itself cannot be extended by another class/object). We’ll spend more time drilling into object later in the series but I just wanted to throw it in here for now as it’s such a heavily used feature.

The key thing to take away from the snippet above is that you can extend a class or object with multiple traits.


Traits vs Abstract Classes

There are 2 differences between traits and abstract classes:

  1. traits cannot have contractor parameters but abstract classes can
  2. you can extend multiple traits but can only extend one abstract class

With regards to point 2, you can actually mix both traits and abstract classes together!


Dealing with Collisions

Since you can extend more than one thing at a time (be it multiple traits, or 1 abstract class + 1 or more traits), one must wonder what happens when some of the members collide.

You might have noticed from our last snippet that both Being and Human defines a name field, but everything still works as expected and you can indeed use the theburningmonk object as a Human or Being.

Ok. What if I extend from 2 traits with clashing members and one of them provides a concrete implementation? My expectation would be for the concrete implementation to fill in for the abstract member with the same name.

and indeed it does.

What if I’m mixing traits with an abstract class?

No problem, still works.

side note: notice that in this second version ProfessorX is extending Psychic first? That’s because in cases where abstract class and traits are both involved, only the traits can be mixed in.

So far so good, but what if both traits/abstract classes provide a concrete implementation for a clashed member?

The safe thing to do here would be for the compiler to crap out and force the developer to rethink what he’s doing rather than springing a nasty surprise later on.

(and yes, it behalves the same way if Light or Dark is an abstract class instead)

This, in my opinion is a much better way to resolve collisions than the Python way.


Dynamic Composition

So far we have mixed in traits when defining a new class or object, but you can do the same in a more ad-hoc fashion.

Of course, all the rules around collision resolution also hold true here.



Whilst traits cannot have constructor parameters, they can have type parameters (ie, they are generic!).

To sneakily weave in the Transformers game I’m working on at Space Ape Games, here’s how you might model a Transformer Combiner as a generic trait.


Stackable Modifications

When you read about traits in Scala, you often hear the phrase “stackable modifications” (Jonas Boner’s real-world Scala slide deck has a nice example).

What makes this interesting (and different from straight up override in inheritance) is how super is modified in an ad-hoc fashion as you compose an object using traits (see Dynamic Composition section above).

This also works if Mutant is an abstract class, and in the definition of an object too.

However, it only work with methods. If you try to override an immutable value then you’ll get a compiler error.

And no, it doesn’t work with variable either, only methods.


self type annotation

Another related topic is the so-called self type annotation feature. It is often used to implement dependency injection in Scala with patterns such as the Cake Pattern.

Where you see code such as below (note the self : A => ), it means the trait B requires A.

Any composing object/class would need to mix in trait A if they want to extend trait B, failure to do so will be met with a swift and deadly compiler error.

This also gives the trait B access to members from A (which includes any members A inherits). For instance.

What’s more, you can mix in multiple traits in the self type.

It’s worth differentiating this “requires” relationship from the “is a” relationship created through inheritance.

In this case, since the Rooney trait is not a Footballer and RecordHolder (which he is in real life, of course) it won’t inherit the members from those traits either.


Interestingly, it’s possible to create cyclic dependencies using self type

which is not possible through inheritance.

As a .Net developer who have seen the damages cyclic references can do, I’m slightly concerned that you could do this in Scala…

That said, in Martin Odersky‘s Programming in Scala, he has an example of how this mutual dependency can be useful in building a spreadsheet, so I’ll keep an open mind for now.

…a new trait, Evaluator. The method needs to access the cells field in class Model to find out about the current values of cells that are referenced in a formula. On the other hand, the Model class needs to call evaluate. Hence, there’s a mutual dependency between the Model and the Evaluator. A good way to express such mutual dependencies between classes was shown in Chapter 27: you use inheritance in one direction and self types in the other.

In the spreadsheet example, class Model inherits from Evaluator and thus gains access to its evaluation method. To go the other way, class Evaluator defines its self type to be Model, like this:

  package org.stairwaybook.scells
  trait Evaluator { thisModel => ...


Finally, as you can see from Martin Odersky‘s example above, you don’t have to use “self” as the name for the self instance.

side note: I’m curious as to how Scala deals with a cyclic dependency where the traits define values that depends on a value on the other trait.

as you can see from all that red, even the code analysis tool in IntelliJ gave up trying to understand what’s going on, but it compiles!

What’s interesting (and again, slightly worrying) is when the fields are evaluated, which actually depends on the order the traits are mixed in.

(new Object with Yin with Yang).motto 

  1. Yin is mixed in, yang.motto is not yet initialised (and therefore null) so Yin.phrase is initialised as null + “yin”
  2. Yang is mixed in, yin.phrase is initialised to “nullyin“, so Yang.motto is now “nullyin” + “yang”
  3. the value of motto is therefore nullyinyang

(new Object with Yang with Yin).motto 

  1. Yang is mixed in, yin.phrase is not yet initialised, so Yang.motto is initialised as null + “yang”
  2. Yin is mixed in, but since motto is already initialised, whatever happens here doesn’t really affect our result
  3. the value of motto is therefore nullyang

ps. please DO NOT try this at work!


So, that’s everything I have learnt about traits in the last week, hope you have found it useful in your path to learn Scala.

Until next time, ciao!



Liked this article? Support me on Patreon and get direct help from me via a private Slack channel or 1-2-1 mentoring.
Subscribe to my newsletter

Hi, I’m Yan. I’m an AWS Serverless Hero and I help companies go faster for less by adopting serverless technologies successfully.

Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.

Hire me.

Skill up your serverless game with this hands-on workshop.

My 4-week Production-Ready Serverless online workshop is back!

This course takes you through building a production-ready serverless web application from testing, deployment, security, all the way through to observability. The motivation for this course is to give you hands-on experience building something with serverless technologies while giving you a broader view of the challenges you will face as the architecture matures and expands.

We will start at the basics and give you a firm introduction to Lambda and all the relevant concepts and service features (including the latest announcements in 2020). And then gradually ramping up and cover a wide array of topics such as API security, testing strategies, CI/CD, secret management, and operational best practices for monitoring and troubleshooting.

If you enrol now you can also get 15% OFF with the promo code “yanprs15”.

Enrol now and SAVE 15%.

Check out my new podcast Real-World Serverless where I talk with engineers who are building amazing things with serverless technologies and discuss the real-world use cases and challenges they face. If you’re interested in what people are actually doing with serverless and what it’s really like to be working with serverless day-to-day, then this is the podcast for you.

Check out my new course, Learn you some Lambda best practice for great good! In this course, you will learn best practices for working with AWS Lambda in terms of performance, cost, security, scalability, resilience and observability. We will also cover latest features from re:Invent 2019 such as Provisioned Concurrency and Lambda Destinations. Enrol now and start learning!

Check out my video course, Complete Guide to AWS Step Functions. In this course, we’ll cover everything you need to know to use AWS Step Functions service effectively. There is something for everyone from beginners to more advanced users looking for design patterns and best practices. Enrol now and start learning!