Start learning free

LESSON 407 OF 414 · OBJECT-ORIENTED PROGRAMMING

Abstract Classes in Scala: abstract, override and extends

Lesson Read the full explanation

TL ; DR:

An abstract class is a class you can't instantiate directly — it's a half-finished template. It can declare methods with no body (abstract methods) that any concrete subclass must implement.


abstract class Animal {
    def speak(): Unit   // no body — concrete
                        // subclasses must provide one
}
class Dog extends Animal {
    override def speak(): Unit = {
        println("Woof")
    }
}


Full lesson:

Sometimes you want to capture shared behavior across a family of classes without committing to one concrete implementation. For example, every Animal can speak(), but exactly how depends on whether it's a Dog or a Cat. That's what abstract classes are for.

Two superpowers

  1. You can't write new Animal() directly — the compiler stops you (Animal is abstract; it cannot be instantiated). You have to pick a concrete subclass.
  2. Any subclass MUST implement every abstract method, or the compiler complains. The abstract class is a contract with teeth.

Mixing abstract and concrete

An abstract class can also have concrete methods (with bodies) and fields. Those are shared by all subclasses for free, just like normal inheritance. Only the methods marked abstract require an override.

Notes by language

  • C# / Java — keyword abstract on the class and on the method.
  • Python — inherit from abc.ABC and decorate the method with @abstractmethod.
  • Scala — keyword abstract on the class; a method with no body is abstract, and the subclass implements it with override def.
  • C++ — a method ending with = 0 is "pure virtual"; a class with any pure virtual method is abstract.

Your task

The abstract Animal class is already defined. Create a concrete Dog subclass and implement the speak method so it prints "Woof". The harness builds a Dog and calls speak().

Expected output:

Woof
STEP 1 OF 2
    Ctrl + Enter to check

    SCALA · OBJECT-ORIENTED PROGRAMMING

    Abstract Classes in Scala, explained

    What an abstract class is

    An abstract class is a partly finished class. It can declare methods without a body, and any concrete subclass must supply them. Because it is unfinished, you can't create an object from it directly. Its purpose is to fix a contract for a family of classes while letting each class decide the details.

    In this lesson every Animal can speak(), but what it says depends on the kind of animal, so Animal declares the method and leaves the body to its subclasses.

    The syntax

    abstract class Animal {
        def speak(): Unit
    }
    

    Two things make this abstract. The class carries the abstract modifier, and speak() has no = and no body. Scala doesn't need an abstract keyword on the method itself: a def without a body is abstract by definition.

    Two rules the compiler enforces

    You can't instantiate an abstract class. Writing new Animal() fails with Animal is abstract; it cannot be instantiated. Writing Animal() without new fails too, with Not found: Animal, because Scala 3 only offers that shorthand for classes that can be instantiated.

    A concrete subclass must implement every abstract member. This subclass leaves speak out:

    class Dog extends Animal
    

    The compiler rejects it with class Dog needs to be abstract, since def speak(): Unit in class Animal is not defined. The abstract class is a contract that is checked when the program is compiled.

    Mixing abstract and concrete members

    An abstract class may also contain ordinary methods and fields. Subclasses inherit those with no extra work:

    abstract class Animal {
        def speak(): Unit
        def describe(): Unit = {
            print("I say: ")
            speak()
        }
    }
    class Dog extends Animal {
        override def speak(): Unit = println("Woof")
    }
    class Cat extends Animal {
        def speak(): Unit = println("Meow")
    }
    

    Calling Dog().describe() prints I say: Woof, and Cat().describe() prints I say: Meow. The shared describe lives in one place, and it calls whichever speak the object has.

    Notice that Cat leaves out override and still compiles. When you implement an abstract member, override is optional. When you replace a member that already has a body, it is required: if Animal.speak() had a body, Dog without override would fail with method speak of type (): Unit needs `override` modifier. The lesson writes override either way, which is a good habit, since the compiler then catches a misspelled method name.

    The exercise, step by step

    The starter code gives you the abstract Animal and a Solution class whose mainFunction already creates a Dog and calls speak() on it. That code doesn't compile until Dog exists.

    1. Declare the subclass. Write class Dog extends Animal in the empty space below Animal. A concrete subclass is the only way to get an object, since Animal itself can't be created.
    2. Implement the method. Inside Dog, write override def speak(): Unit with a body that calls println("Woof"). The signature must match the abstract one: same name, no parameters, return type Unit.

    The solution in Scala

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

    Details worth knowing:

    • Dog() without new. Scala 3 lets you create an instance of a concrete class this way. It is the same as new Dog().
    • The type of rex. It is inferred as Dog. Writing val rex: Animal = Dog() would also work and would call the same method, because the object decides which speak runs.
    • Unit. The return type for methods that are called for their side effect, here printing.

    Common mistakes

    • Leaving out extends Animal. Then Dog is an unrelated class, and defining override def speak() in it fails because there is nothing to override.
    • Changing the signature. def speak(times: Int): Unit is a different method. The abstract speak() stays unimplemented, and the compiler asks for it.
    • Misspelling the name. With override, def speek() is reported as overriding nothing. Without it, it quietly becomes a new method, and the missing implementation of speak is reported instead.
    • Printing with the wrong text. The test expects exactly Woof.

    Key takeaways

    • An abstract class has the abstract modifier and may contain methods without bodies.
    • You can't instantiate it; you extend it with a concrete class that implements every abstract member.
    • Concrete members of the abstract class are inherited by all subclasses.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free