Scala - Extension Methods



You can add new functionality to existing types without modifying their original code and using inheritance.

Extension Methods

Extension methods are methods that can be added to existing classes and objects. You can add extension methods even if you do not have access to their original source code. Extension methods are used when you want to add utility functions to classes that you do not own and cannot change. So, your code will be more expressive and readable. You can call more methods on instances of these types directly.

Definition

Extension method is a method added to an existing type using implicit conversions and using the extension keyword in Scala 3. So, you can add new methods to existing types without modifying their original code.

Syntax

The syntax of extension methods in Scala 3 is -

extension (x: Type)
  def methodName(params: Type*): ReturnType = {
    // method body
  }

Example of Extension Methods

The following example shows defining and using an extension method in Scala programming −

object Demo {
  extension (s: String)
    def greet: String = s"Hello, $s!"

  def main(args: Array[String]): Unit = {
    println("World".greet) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Hello, World!

In the example, the greet method is added to String type using extension method. So you can call greet directly on any String instance.

Advantages of Extension Methods

There are various advantages of extension methods in Scala. You can add functionality to existing types without modifying their original code. So you can reuse code and reduce redundancy.

You can encapsulate utility functions and keep them close to the types they extend. So you can organize code properly. You can also enhance types with new methods when you do not have control over the source code of the types.

Extension Methods with Parameters

Extension methods can also take parameters. So it provides even more flexibility.

Syntax

The syntax of extension methods with parameters is -

extension (x: Type)
  def methodName(param1: ParamType1, param2: ParamType2): ReturnType = {
    // method body
  }

Example

Consider the example of an extension method with parameters in Scala programming -

object Demo {
  extension (s: String)
    def repeat(n: Int): String = s * n

  def main(args: Array[String]): Unit = {
    println("Hello".repeat(3))  
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

HelloHelloHello

In the example, the repeat method is added to the String type. So, you can repeat the string a specified number of times.

Chaining Extension Methods

You can chain multiple extension methods together. So, your code will be more expressive.

Syntax

The syntax for chaining extension methods is -

extension (x: Type)
  def firstExtension(params: Type*): ReturnType = {
    // first method body
  }

extension (x: Type)
  def secondExtension(params: Type*): ReturnType = {
    // second method body
  }

Example

Consider the example of chaining extension methods in Scala programming −

object Demo {
  extension (s: String)
    def capitalizeWords: String = s.split(" ").map(_.capitalize).mkString(" ")
    def reverseWords: String = s.split(" ").reverse.mkString(" ")

  def main(args: Array[String]): Unit = {
    println("hello world".capitalizeWords.reverseWords) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

World Hello

In the example, the capitalizeWords and reverseWords methods are added to the String type. You can chain these methods together to achieve more complex transformations.

Extension Methods for Collections

You can use extension methods with collections. You can add custom methods to collections to simplify operations.

Syntax

The syntax for extension methods with collections is -

extension [T](list: List[T])
  def methodName(params: Type*): ReturnType = {
    // method body
  }

Example

Consider the example of adding an extension method to a List in Scala programming -

object Demo {
  extension [T](list: List[T])
    def second: Option[T] = list.drop(1).headOption

  def main(args: Array[String]): Unit = {
    val nums = List(1, 2, 3, 4)
    println(nums.second)  // Output: Some(2)

    val emptyList = List()
    println(emptyList.second)  // Output: None
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Some(2)
None

In the example, the second method is added to the List type. So you can get the second element of the list, if it exists.

Extension Methods with Type Classes

You can use extension methods in conjunction with type classes to provide more generic and reusable code.

Syntax

The syntax for extension methods with type classes is -

trait TypeClass[A] {
  def method(value: A): ReturnType
}

object TypeClassInstances {
  implicit val typeClassInstance: TypeClass[Type] = new TypeClass[Type] {
    def method(value: Type): ReturnType = {
      // method implementation
    }
  }
}

extension [A](value: A)(using typeClass: TypeClass[A])
  def extensionMethod: ReturnType = typeClass.method(value)

Example

Consider the example of using extension methods with type classes in Scala programming -

trait Printable[A] {
  def format(value: A): String
}

object PrintableInstances {
  implicit val printableInt: Printable[Int] = new Printable[Int] {
    def format(value: Int): String = s"Int($value)"
  }

  implicit val printableString: Printable[String] = new Printable[String] {
    def format(value: String): String = s"String($value)"
  }
}

object Demo {
  import PrintableInstances._

  extension [A](value: A)(using printable: Printable[A])
    def print: String = printable.format(value)

  def main(args: Array[String]): Unit = {
    println(123.print)         
    println("hello".print)     
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Int(123)
String(hello)

In the example, the print method is added to any type A that has implicit Printable[A] instance. So you can print different types in a consistent format.

Extension Methods Summary

  • You can add new functionality to existing types without modifying their original code.
  • It enhances code reuse, encapsulation, and flexibility.
  • You can define extension methods using the extension keyword in Scala 3.
  • Extension methods can take parameters and be chained together for more expressive code.
  • You can use extension methods with collections to simplify operations.
  • You can use extension methods combined with type classes. It provides more generic and reusable code.
Advertisements