Scala – Implicit Class

Ok so this isn’t a deep dive into implicit’s in scala but rather a reminder on how helpful they can be. The camp on using implicit in scala is divided as you can use them in several different ways and like everyone you’ll go crazy and use them everywhere, then you’ll stop.

Anyway implicit classes are an ideal way to add functionality to an existing type, huh? Ok so I get fed up of seeing this

val time =
val someSpecialTime = SomeSpecialTime(time)

The code to me doesn’t read naturally anymore after using scala and I’d prefer time.toSomeSpecialTime, well there is a way if you use an implicit class:

object Converters {
  implicit class LocalTimeToSpecialTime(val localTime: LocalDateTime) extends AnyVal {
    def toSomeSpecialTime = SomeSpecialTime(time)
    def doSomthingElse = AnotherSpecialTime(time)

Now I can import the class and use it as I want.

The implicit class however can not be top level and MUST be defined in a scope where method calls are allowed -> package, class, object. I tend to wrap them inside an object.

I like to use them as a kind of factory, where a string is passed in and the correct type is returned.

def toSurfaceExtrapMethod: SurfExtrapolationMethod = {
  value match {
    case "SE_NONE" => SurfExtrapolationMethod.NONE()
    case SE_FLATLINE" => SurfExtrapolationMethod.FLATLINE()
    case "SE_FLATLINE_TO_ZERO" => SurfExtrapolationMethod.FLATLINE_TO_ZERO()
    case "SE_WITHIN_TOLERANCE" => SurfExtrapolationMethod.WITHIN_TOLERANCE()

Also it’s possible to pass in values so you can have something like

def toRangeType(fixedRange: Option[FixedRange] = None): RangeType = {
  value match {
    case "FIT_BOTH" => RangeType.FitBoth()
    case "FIT_END" => RangeType.FitEnd()
    case "FIXED" => RangeType.Fixed(fixedRange.get)
    case "MIN_START" => RangeType.MinStart()

So you can do something like

val rangeType = "FIXED".toRangeType(Some(FixedRange.FALSE))

Folding observables with Scala

I had a bunch of observables that I wanted to merge into a single observable and then subscribe to it. I knew that I could use merge but had an unknown sequence size of observables, so how could I do it? Easy I can use the merge and fold functions:-

val obs1: Observable[Int] = Observable.from(Seq(1,2,3,4,5))
val obs2: Observable[Int] = Observable.from(Seq(6,7,8,8,10))
val obs3: Observable[Int] = Observable.from(Seq(11,12,13,14))

val totalObservable = Seq(obs1, obs2, obs3)
  .fold(Observable.just[Int]())((a,b) => a.merge(b))

totalObservable.foreach(x => println(s"This is the value ${x}"))

The fold takes in an initial value, in this case “Observable.just[Int]()” followed by the aggregation function “a.merge(b)”. It took me about 30 mins to figure out the syntax, especially around the initial value but the code is clean and clear.