Scala - Union Types


Scala Union Types is used to define a type that can be one of various possible types. So you can have more flexible type definitions. Union type can reduce the need for overloading methods. These are used when a function can accept multiple different types as parameters and return multiple different types.

Declaring Union Types

The following is the syntax for declaring a union type variable.

Syntax

def exampleMethod(x: Int | String): Unit = {
  x match {
    case i: Int => println(s"Integer: $i")
    case s: String => println(s"String: $s")
  }
}

Here, exampleMethod is declared with a parameter x that can be either an Int or a String. The union type Int | String specifies that x can be of either type.

Union Types in Methods

Below is an example program showing how to create and use a method with a union type parameter.

Example

object Demo {
   def main(args: Array[String]) = {
      def exampleMethod(x: Int | String): Unit = {
         x match {
            case i: Int => println(s"Integer: $i")
            case s: String => println(s"String: $s")
         }
      }

      // Call method with an integer
      exampleMethod(42)
      // Call method with a string
      exampleMethod("Scala")
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Integer: 42
String: Scala

Union Types in Function Parameters

Union types can also be used in function parameters. So functions can accept arguments of different types.

Example

Try following example of union types in function parameters -

object Demo {
   def main(args: Array[String]) = {
      def processInput(input: Int | Double | String): Unit = {
         input match {
            case i: Int => println(s"Processing Int: $i")
            case d: Double => println(s"Processing Double: $d")
            case s: String => println(s"Processing String: $s")
         }
      }

      // Call function with an integer
      processInput(10)
      // Call function with a double
      processInput(3.14)
      // Call function with a string
      processInput("Hello, Scala!")
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Processing Int: 10
Processing Double: 3.14
Processing String: Hello, Scala!

Union Types with Type Aliases

You can use type aliases to simplify the usage of union types. It is used when these are used frequently.

Example

Try following example of union types with type aliases -

object Demo {
   type IntOrString = Int | String

   def main(args: Array[String]) = {
      def printValue(value: IntOrString): Unit = {
         value match {
            case i: Int => println(s"Integer: $i")
            case s: String => println(s"String: $s")
         }
      }

      // Call function with an integer
      printValue(100)
      // Call function with a string
      printValue("Scala Union Types")
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Integer: 100
String: Scala Union Types

Returning Union Types from Methods

You can use union types as return types for methods. So a method can return different types based on some condition.

Example

Try following example of returning union type from method -

object Demo {
   def getValue(flag: Boolean): Int | String = {
      if (flag) 42 else "Scala"
   }

   def main(args: Array[String]) = {
      // Call method with true
      println(getValue(true))
      // Call method with false
      println(getValue(false))
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

42
Scala

Union Types with Higher-Order Functions

You can use union types combined with higher-order functions to process elements of different types in a collection.

Example

Try following example of union types in higher order function -

object Demo {
   def main(args: Array[String]) = {
      val mixedList: List[Int | String] = List(1, "two", 3, "four")

      mixedList.foreach {
         case i: Int => println(s"Integer: $i")
         case s: String => println(s"String: $s")
      }

      // Transform the list elements
      val transformedList = mixedList.map {
         case i: Int => i * 2
         case s: String => s.toUpperCase
      }

      println(transformedList)
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Integer: 1
String: two
Integer: 3
String: four
List(2, TWO, 6, FOUR)

Union Types with Default Parameter Values

You can also use union types with default parameter values in functions and methods. So, there will be flexibility in how the function can be called. So, functions can handle different types of input with default values.

Example

The following example demonstrates union types with default parameter values –

object Demo {
   def main(args: Array[String]) = {
      def displayMessage(message: Int | String = "Default Message"): Unit = {
         message match {
            case i: Int => println(s"Integer: $i")
            case s: String => println(s"String: $s")
         }
      }

      // Call function with default parameter
      displayMessage()
      // Call function with an integer
      displayMessage(42)
      // Call function with a string
      displayMessage("Hello Scala")
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

String: Default Message
Integer: 42
String: Hello Scala

Using Union Types in Constructors

You can use union types in class constructors for flexible initialization of class instances with different types.

Example

Try following example of union types in constructor -

object Demo {
   class Container(value: Int | String) {
      def display(): Unit = {
         value match {
            case i: Int => println(s"Integer: $i")
            case s: String => println(s"String: $s")
         }
      }
   }

   def main(args: Array[String]) = {
      // Create instances with different types
      val intContainer = new Container(42)
      val stringContainer = new Container("Scala")

      // Display values
      intContainer.display()
      stringContainer.display()
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Integer: 42
String: Scala

Union Types in Collections

You can use union types within collections, for lists, sets, and other collections to hold elements of different types. So, there will be flexibility for various data types in a unified collection.

Example

Try following example of union types in collection -

object Demo {
   def main(args: Array[String]) = {
      val collection: List[Int | String] = List(1, "two", 3, "four")

      collection.foreach {
         case i: Int => println(s"Integer: $i")
         case s: String => println(s"String: $s")
      }
   }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Integer: 1
String: two
Integer: 3
String: four

Union Types Summary

  • Union types in Scala are used for more flexible type definitions using variables that can be one of various types.
  • You can use union types in method parameters, function parameters, and collections.
  • Type aliases can simplify the usage of union types.
  • Union types can reduce the need for overloading methods.
  • Union types can be used as return types, in case classes, and with higher-order functions to process elements of different types.