St.Antario
St.Antario

Reputation: 27385

Bring implicit to scope

I have a trait

trait Tr{
    def logic: Option[() => Unit] = None
    def apply(): Unit = logic match {
         case Some(l) => l()
         case None =>
    }
}

object Tr{
    implicit def procLogic2Opt(processingLogic: () => Unit): Option[() => Unit] 
= Some(processingLogic)
}

The thing is when subclassing the trait I have to import Tr._ explicitly to bring implicits into a scope. Like this

import Tr._ //otherwise does not compile

class Trrr extends Tr{
    override def processingLogic = () => println("test")
}

Is there a way to do it without importing explicitly? How could I redesign it?

Upvotes: 0

Views: 386

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170745

Because the client is supposed to call only apply. I thought it's not necessary for subclassers to know that Option is required

So, why require it?

trait Tr {
    protected val logic: () => Unit = () => {}
    def apply(): Unit = logic()
}

class Trrr extends Tr{
   override val logic = () => println("test")
}

(val logic to avoid recreating it each time.)

Upvotes: 1

dk14
dk14

Reputation: 22374

Answering the headline question, if you really really really need it, move your implicit to trait:

trait Tr{
    implicit def procLogic2Opt(...) = ...
}

This is not always a good practice though, because it's hard to find which implicit is responsible.

A story: In my previous project we had Logging trait with implicit (kind of) T => Any which we inherited everywhere - imagine how many unexpected type conversions we had. Same goes for () => Unit as many people might inherit your trait without even knowing about your implicit and wonder why functions other than apply work when they shouldn't.


Besides implicit conversions (like your procLogic2Opt) are a bad practice as well (almost always).

Quote from here:

Do not use implicits to do automatic conversions between similar datatypes (for example, converting a list to a stream); these are better done explicitly because the types have different semantics, and the reader should beware of these implications.

More precisely about your case: Scala Option implicit conversion - Bad practice or missing feature?

Use implicit-classes instead:

implicit class RichSomething(something: Something){
  def toSomethingElse = ...
}

something.toSomethingElse

As mentioned in the comments your case is even simpler

Some(() => println("aaaa"))

class Trrr extends Tr{
   override def logic = Some(() => println("test"))
}

This will give you explicit, easily understandable and discoverable types without wondering how () => Unit became an Option[() => Unit]

Upvotes: 3

Related Questions