Scala - Singleton Type Operator



Singleton type operator is used to create types that are tied to specific instances. It is used in certain values that must be exactly equal to specific instances. Thereby you can prevent many kinds of runtime errors by catching them at compile time.

Singleton Type Operator

The primary purpose of the Singleton Type Operator is to enforce that certain values are exactly equal to specific instances. You can create precise and type-safe APIs that only the intended values are used in specific contexts. It is to guarantee that certain constants are used consistently throughout your code.

You can prevent memory space wastage by restricting the instantiation of objects. You can also potentially error during compile time rather than at runtime.

How to Use Singleton Type Operator in Scala?

To use the Singleton Type Operator in Scala, you need to follow these steps -

  • Define a value with a specific type.
  • Use the Singleton Type Operator to ensure that a value must be exactly equal to this specific instance.

These are some examples using singleton type operators in Scala.

Example 1: Enforcing Specific Value Constraints

You can define a type that is exactly equal to a specific instance using the Singleton Type Operator. So, only the specified value can be used in certain contexts.

object Demo {
   // This value has the singleton type 42
  val specificValue: 42 = 42  

  def printSpecificValue(value: 42): Unit = {
    println(s"The value is $value")
  }

  def main(args: Array[String]): Unit = {
    printSpecificValue(specificValue)
    // The following line would cause a compile-time error
    // printSpecificValue(43)
  }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

The value is 42

The above code will print the value 42 if the specified value is used. If any other value is attempted, it will cause a compile-time error.

Example 2: Accepting Only Specific Instances

Following is the example which shows you how to use Singleton Type for only a specific instance can be passed to a function.

object Demo {
  val allowedValue: "allowed" = "allowed"

  def acceptOnlyAllowed(value: "allowed"): Unit = {
    println(s"Accepted value: $value")
  }

  def main(args: Array[String]): Unit = {
    acceptOnlyAllowed(allowedValue)
    // The following line would cause a compile-time error
    // acceptOnlyAllowed("not allowed")
  }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Accepted value: allowed

The above code will print the accepted value if it matches the allowed instance. Any other value will result in a compile-time error.

Example 3: Using Singleton Type in a Class

Following is the example which shows you how to use Singleton Type in a class to enforce specific values for its fields.

class Config(val mode: "production" | "development")

object Demo {
  def printConfig(config: Config): Unit = {
    println(s"Config mode: ${config.mode}")
  }

  def main(args: Array[String]): Unit = {
    val productionConfig = new Config("production")
    val developmentConfig = new Config("development")

    printConfig(productionConfig)
    printConfig(developmentConfig)
    // The following line would cause a compile-time error
    // val invalidConfig = new Config("test")
  }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Config mode: production
Config mode: development

Any other mode will result in a compile-time error.

Example 4: Type-Safe Constants

Following is the example which shows you how to use Singleton Types to create type-safe constants. So only specific values are used in the program.

object Constants {
  val Pi: 3.14159 = 3.14159
  val Euler: 2.71828 = 2.71828
}

object Demo {
  def printConstant(constant: 3.14159 | 2.71828): Unit = {
    println(s"Constant value: $constant")
  }

  def main(args: Array[String]): Unit = {
    printConstant(Constants.Pi)
    printConstant(Constants.Euler)
    // The following line would cause a compile-time error
    // printConstant(1.61803)
  }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Constant value: 3.14159
Constant value: 2.71828

The above code will print the constant value if it matches the allowed instances. Any other value will result in a compile-time error.

Example 5: Pattern Matching with Singleton Types

Following is the example which shows you how to use Singleton Types in pattern matching to narrow down cases to specific values.

object Demo {
  val optionOne: "Option1" = "Option1"
  val optionTwo: "Option2" = "Option2"

  def handleOption(option: "Option1" | "Option2"): Unit = {
    option match {
      case `optionOne` => println("Handling Option 1")
      case `optionTwo` => println("Handling Option 2")
    }
  }

  def main(args: Array[String]): Unit = {
    handleOption(optionOne)
    handleOption(optionTwo)
    // The following line would cause a compile-time error
    // handleOption("Option3")
  }
}

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

Command

> scalac Demo.scala
> scala Demo

Output

Handling Option 1
Handling Option 2

The above code will print the handling message if the option matches the allowed instances. Any other option will result in a compile-time error.

Singleton Type Operator Summary

  • Singleton type operator is used to enforce that certain values are exactly equal to specific instances.
  • You can use Singleton types in method parameters, class fields, and pattern matching.
  • Singleton types ensure type-safe APIs by restricting values to specific instances.
  • You can prevent runtime errors by catching invalid values at compile time.
  • Singleton types can be used to define constants with precise type constraints.
Advertisements