Forem

Cover image for Implicit Conversions in Scala
Montegasppα Cacilhας
Montegasppα Cacilhας

Posted on • Edited on

2

Implicit Conversions in Scala

Scala (in version 2.13 while I write) has a powerful conversion system based on its implicits system.

I updated the codes to Scala 3.x.

It works by expanding implicit methods and classes into a more complex structure, which would be way harder to code if it needs to be done explicitly.

Scala

We’re gonna talk about three ways to implement implicit conversions and their expansions.

Implicit methods

Take the double value sequence:

Seq(0.4, 1.8, 2.2)
Enter fullscreen mode Exit fullscreen mode

In this case it’s a short list, but it could be hundreds larger. One needs only their ceiling integer values, so one must a way to convert the values.

One can use an implicit method:

implicit def double2int(value: Double): Int = value.ceil.toInt

val values: Seq[Int] = Seq(0.4, 1.8, 2.2)
Enter fullscreen mode Exit fullscreen mode

The value of values is:

Seq(1, 2, 3)
Enter fullscreen mode Exit fullscreen mode

It’s expanded to:

def double2int(value: Double): Int = value.ceil.toInt

val values: Seq[Int] = Seq(0.4, 1.8, 2.2) map double2int
Enter fullscreen mode Exit fullscreen mode

Implicit classes

Implicit classes are the way to inject methods into existent types.

For instance, let’s create a string method to generate the XML node from it:

implicit class XMLString(value: String):
  def toXML: Option[NodeSeq] = Try(XML loadString value).toOption

val source = getDataFromOutsideSource() // : String

val node = source.toXML
Enter fullscreen mode Exit fullscreen mode

It expands to:

class XMLString(value: String) {
  def toXML: Option[NodeSeq] = Try(XML loadString value).toOption
}

object XMLString extends (String => XMLString) {
  def apply(value: String): XMLString = new XMLString(value)
}

val source: String = getDataFromOutsideSource()

val node: Option[NodeSeq] = XMLString(source).toXML
Enter fullscreen mode Exit fullscreen mode

Note that whenever .toXML is called, a new XMLString is created.

Implicit value classes

Value classes are lightweight Scala resources, which don’t create new instance each call. Instead, every value class uses a companion object to envelope the methods, and calls them from it.

Consider the following example, a method to determine whether a double is integral:

implicit class IntegralDouble(val value: Double) extends AnyVal:
  def isIntegral: Boolean = value % 1 == 0

val value = getSomeFloatPointValue() // : Double

if (value.isIntegral)
  doSomeMathWith(value)
Enter fullscreen mode Exit fullscreen mode

Which expands to:

object IntegralDouble {
  def isIntegral$expansion(value: Double): Boolean = value % 1.0 == 0.0
}

val value: Double = getSomeFloatPointValue()

if (IntegralDouble.isIntegral$expansion(value))
  doSomeMathWith(value)
Enter fullscreen mode Exit fullscreen mode

No instance is created on .isIntegral call.

Note: value classes are tagged by inheriting AnyVal, and need a value of type * <: AnyVal, i.e., Boolean, Byte, Char, Double, Float, Int, Long, Short, Unit, and their literal-based singleton types.


Original post in Kodumaro.

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay