Anonymous Classes in Scala

This post is part 6 of the Object Oriented Programming in Scala series.

We learned about Inheritance in Scala in a previous blog post in this series. In that post, we discussed how in Scala (and as a general rule in programming), you can’t instantiate an abstract class.

Instantiate an Abstract Class ?

But is that actually true? Look at the code below:

abstract class Animal {
  def eat: Unit
}

val funnyAnimal: Animal = new Animal {
  override def eat: Unit = println("I am a funny animal")
}

This code works, and does appear to instantiate an abstract class. So what exactly is going on here?

Well, we didn’t actually create an instance of the abstract class. It just appears that way. It is actually a real class that we instantiated.

If we do:

println(funnyAnimal.getClass)

The following is printed out to the console:

class scalaBasics.objectOriented.AnonymousClasses$$anon$1

An Anonymous Class

With the code that we wrote earlier, the compiler took everything after the new keyword, i.e. :

Animal {
  override def eat: Unit = println("I am a funny animal")
}

And created a class with the long name that we saw above.

It then instantiated that class right away, and assigned it to the funnyAnimal value. This is called an Anonymous Class.

To visualise this, look at the code where we originally assigned a new instance of Animal to the funnyAnimal value. To the compiler, it looks like this:

class AnonymousClasses$$anon$1 extends Animal {
  override def eat: Unit = println("I am a funny animal")
}

And when we use it, the compiler instantiates that class instead:

  val funnyAnimal: Animal = new AnonymousClasses$$anon$1

With anonymous classes, the compiler does a lot of work behind the scenes. This allows us to abstract that complexity away from our code.

Pass Constructor Arguments to an Anonymous Class

Let’s say we had the following simple Person class:

class Person(name: String) {
  def sayHi: Unit = println(s"Hi, my name is $name, how can I help?")
}

If we wanted to instantiate an anonymous class for Person, with the sayHi() method overridden on the spot:

val bob = new Person {
  override def sayHi: Unit = println("Hi, my name is Bob, what's going on?")
}

The above would work fine, except the compiler is giving an error because we are missing the parameters of the Person class. You would have to pass in the parameters, i.e.:

val bob = new Person("Bob") {
  override def sayHi: Unit = println("Hi, my name is Bob, what's going on?")
}

We must always pass in the required parameters for an anonymous class implementation, even if they aren’t used in the anonymous class definition.

Anonymous Classes for both Abstract and Non-Abstract Data Types

Notice that in the above code, the Person class is not declared abstract. The anonymous class that we are declaring of Person for Bob works, even though Person is not abstract in any way.

Anonymous classes work for abstract and non-abstract data types just as well.

This means that we can use a trait instead of an abstract class, e.g.:

trait Animal {
  def eat: Unit
}

We can instantiate this trait, and provide a definition:

val predator = new Animal {
  override def eat: Unit = println("I am a predator eating")
}

Summary

In this post, we learned how to create and immediately instantiate anonymous classes in our Scala code.

When creating anonymous classes, we need to remember to pass in the required constructor arguments if needed.

We also need to remember to implement all abstract fields or methods in the anonymous class.

Finally, remember that anonymous classes work for both traits and classes, whether they are abstract or not.

Source Code

As always, the source code for this post is available on Github.