Reflection in Scala
In this lesson, you will learn about reflection in Scala. Reflection allows a program to inspect and interact with its own structure at runtime.
Using reflection, you can examine classes, methods, fields, annotations, and even create objects dynamically while the program is running.
What Is Reflection?
Reflection is the ability of a program to:
- Inspect classes and objects at runtime
- Discover methods, fields, and constructors
- Invoke methods dynamically
- Create instances without knowing their types at compile time
Reflection is powerful but should be used carefully, as it bypasses some compile-time safety.
Why Use Reflection?
Reflection is useful in advanced scenarios such as:
- Frameworks and libraries
- Dependency injection systems
- Serialization and deserialization
- ORMs (Object-Relational Mappers)
- Plugin architectures
Scala Reflection vs Java Reflection
Scala provides its own reflection API on top of Java reflection. It understands Scala-specific features such as:
- Traits
- Case classes
- Companion objects
- Type parameters
Scala reflection is found in the scala.reflect.runtime package.
Importing Scala Reflection
To use reflection, you must import the runtime mirror.
import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
The mirror connects your code to runtime type information.
Getting Type Information
You can inspect type information of a class using typeOf.
case class Person(name: String, age: Int)
val tpe = typeOf[Person]
println(tpe)
This prints the structure of the Person class.
Inspecting Class Members
Reflection allows you to inspect fields and methods of a class.
val members = typeOf[Person].members
members.foreach { member =>
println(member.name)
}
This lists all members, including methods and fields.
Creating Objects Dynamically
You can create instances of a class dynamically using reflection.
val classSymbol = typeOf[Person].typeSymbol.asClass
val classMirror = currentMirror.reflectClass(classSymbol)
val constructor = typeOf[Person].decl(termNames.CONSTRUCTOR).asMethod
val constructorMirror = classMirror.reflectConstructor(constructor)
val person = constructorMirror("Alice", 30)
println(person)
This creates a Person object without calling the constructor directly.
Invoking Methods Dynamically
Reflection can invoke methods at runtime.
case class Calculator() {
def add(a: Int, b: Int): Int = a + b
}
val calc = Calculator()
val instanceMirror = currentMirror.reflect(calc)
val methodSymbol = typeOf[Calculator].decl(TermName("add")).asMethod
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
println(methodMirror(3, 4))
This dynamically calls the add method.
Reflection and Case Classes
Case classes are commonly used with reflection for serialization and data mapping.
Reflection makes it possible to:
- Extract field names
- Access constructor parameters
- Map objects dynamically
Performance Considerations
Reflection is slower than normal method calls because:
- Type checks happen at runtime
- Optimizations are limited
For performance-critical code, avoid reflection when possible.
Best Practices
- Use reflection only when necessary
- Prefer compile-time safety over dynamic access
- Cache reflective lookups if reused
- Document reflective code clearly
📝 Practice Exercises
Exercise 1
Use reflection to print all methods of a class.
Exercise 2
Create an object dynamically using reflection.
Exercise 3
Invoke a method on an object using reflection.
✅ Practice Answers
Answer 1
typeOf[String].members.foreach(m => println(m.name))
Answer 2
case class User(id: Int)
val cls = typeOf[User].typeSymbol.asClass
val mirror = currentMirror.reflectClass(cls)
val ctor = typeOf[User].decl(termNames.CONSTRUCTOR).asMethod
val ctorMirror = mirror.reflectConstructor(ctor)
println(ctorMirror(1))
Answer 3
case class Greeter() {
def greet(name: String) = s"Hello, $name"
}
val g = Greeter()
val m = currentMirror.reflect(g)
val method = typeOf[Greeter].decl(TermName("greet")).asMethod
println(m.reflectMethod(method)("Scala"))
What’s Next?
In the next lesson, you will explore Scala 3 Features and understand how modern Scala improves syntax, safety, and expressiveness.