Start learning free

LESSON 408 OF 414 · OBJECT-ORIENTED PROGRAMMING

Interfaces in Scala: Traits and extends

Lesson Read the full explanation

TL ; DR:

An interface (in Scala, usually a trait) is a pure contract — a list of methods that a class promises to implement, with no shared data and no shared code. Unlike inheritance ("is a"), interfaces express "can do".


trait Speaker {
    def speak(): Unit
}
class Dog extends Speaker {
    override def speak(): Unit = {
        println("Woof")
    }
}


Full lesson:

An interface defines what a class can do, not how it does it or what it is. A Truck, a Robot, and a Drone aren't the same kind of thing — but they can all move(). You'd put move() in a Movable trait and have each one implement it.

Interface vs abstract class

Abstract classInterface
Has fieldsYesUsually no
Has method bodiesYes (some)No (or default impls only)
Multiple "inheritance"Usually noYes — a class can implement many interfaces
Models"is a""can do"

A class inherits from at most one parent class but can implement many interfaces. That's why interfaces are the right tool for cross-cutting capabilities like Comparable, Serializable, Iterable, etc.

The language landscape

  • C# / Java — first-class interface keyword. C# uses : for both inheritance and implementation; Scala uses extends for both a parent class and the first trait, then with for further traits (there is no implements).
  • Python — no separate interface; abstract base classes (ABCs) with all-abstract methods serve the same role.
  • Scala — no interface keyword; a trait with abstract methods plays that role, and a class can mix in several traits.
  • C++ — a class with only pure-virtual methods is an interface. Multiple inheritance lets a class implement several.

Your task

The Speaker trait is already declared. Create a Dog class that extends it, with a speak() method that prints "Woof".

Expected output:

Woof
STEP 1 OF 2
    Ctrl + Enter to check

    SCALA · OBJECT-ORIENTED PROGRAMMING

    Interfaces in Scala, explained

    What an interface is

    An interface describes what a class can do without saying how it does it. A Truck, a Robot and a Drone are different kinds of things, but all of them can move. A Movable contract that lists move() lets code treat them alike without forcing them into one family tree.

    Inheritance models "is a": a Dog is an Animal. An interface models "can do": a Dog can speak. A class has one parent class but may adopt many such contracts.

    Traits are Scala's interfaces

    Scala has no interface keyword. Its tool for this job is the trait:

    trait Speaker {
        def speak(): Unit
    }
    

    As in an abstract class, a def without a body is abstract. A class adopts the trait with extends, and it then has to implement every abstract member:

    class Dog extends Speaker {
        override def speak(): Unit = {
            println("Woof")
        }
    }
    

    Where Java uses two keywords, extends for a parent class and implements for an interface, Scala uses extends for the first parent, whether it is a class or a trait. Scala has no implements keyword.

    If Dog leaves out speak, the compiler reports class Dog needs to be abstract, since def speak(): Unit in trait Speaker is not defined.

    Several traits at once

    The first parent comes after extends. Every further trait is added with with:

    trait Speaker { def speak(): Unit }
    trait Mover { def move(): Unit = println("moving") }
    
    class Dog extends Speaker with Mover {
        override def speak(): Unit = println("Woof")
    }
    
    class Base
    class Child extends Base with Speaker {
        def speak(): Unit = println("child")
    }
    

    Dog().speak() prints Woof, and Dog().move() prints moving. Child shows a class with a real parent class that also adopts a trait. This is the "many contracts" part: one class, many capabilities.

    The Mover trait also shows that a Scala trait may carry code. move() has a body, so every class that adopts Mover gets it for free, and may override it. A trait with only abstract members is the pure contract the lesson describes. A trait with concrete members goes further than a classic interface.

    Trait versus abstract class

    Abstract classTrait
    Bodies for some methodsYesYes
    A class can extend severalNo, one parent classYes, joined with with
    Usual role"is a""can do"

    As a rule of thumb, reach for a trait when you are describing a capability that unrelated classes can share, and for an abstract class when the classes are variants of one thing and share state.

    Programming against the contract

    Because Dog adopts Speaker, a Dog can be stored in a variable of type Speaker. Code that holds a Speaker knows only that it has speak(), and the call reaches the real object's implementation:

    val rex: Speaker = Dog()
    rex.speak()   // Woof
    

    You can't create a trait instance with Speaker(), which fails with Not found: Speaker. You always create a class that adopts it. Scala 3 does offer an anonymous class when you need a one-off implementation:

    val s = new Speaker { def speak(): Unit = println("anon") }
    s.speak()   // anon
    

    The exercise, step by step

    The starter code declares the Speaker trait and a mainFunction that already builds a Dog and calls speak() on it as a Speaker. It needs a Dog.

    1. Declare Dog. Write class Dog extends Speaker below the trait. The trait is adopted with extends.
    2. Implement speak. Add override def speak(): Unit and make its body print Woof. For an abstract member override is optional, but writing it makes the compiler check that the signature really matches a member of the trait.

    The solution in Scala

    trait Speaker {
        def speak(): Unit
    }
    
    class Dog extends Speaker {
        override def speak(): Unit = {
            println("Woof")
        }
    }
    
    class Solution {
        def mainFunction(): Unit = {
            val rex: Speaker = Dog()
            rex.speak()
        }
    }
    

    The parts to notice are the annotation val rex: Speaker, which hides the fact that the object is a Dog, and the call to Dog() without new, which Scala 3 allows for concrete classes.

    Common mistakes

    • Writing implements. It isn't a Scala keyword; use extends.
    • Using with first. The first parent follows extends; with only adds further traits.
    • Changing the signature. A method named speak with different parameters doesn't implement the trait's speak().
    • Forgetting Unit or the body. The method has to be a full definition with = and a body.

    Key takeaways

    • A trait is Scala's interface: it declares what a class can do.
    • A class adopts a trait with extends, and more traits with with.
    • The class must implement every abstract member of its traits.
    • Traits may also contain concrete members, which adopting classes inherit.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free