We're planting a tree for every job application! Click here to learn more

Implicit Conversions in Scala

Rodrigo Montegasppα Cacilhας

4 Jan 2021

2 min read

Implicit Conversions in Scala
  • Scala

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

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

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)

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)

The value of values is:

Seq(1, 2, 3)

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

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

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

Note that everytime .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)

Which expands to:

class IntegralDouble(val value: Double): extends AnyVal {
  def isIntegral: Boolean = IntegralDouble isIntegral$expansion value
}

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

val value: Double = getSomeFloatPointValue()

if (IntegralDouble.isIntegral$expansion(value))
  doSomeMathWith(value)

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.

Did you like this article?

Rodrigo Montegasppα Cacilhας

My name is Legion, for we are many.

See other articles by Rodrigo

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub