1

I started adding some implicit conversions to my code base. I didn't really research how this was done in Scala or look at many examples, so I implemented these as traits. For example, this snippet lets you test the schema of a Spark DataFrame:

trait DataFrameImplicits {

  implicit class DataFrameTest(df: DataFrame) {

    def testInputFields(requiredCols: Map[String, DataType]): Unit = {
      requiredCols.foreach { case (colName: String, colType: DataType) =>
        if (!df.schema.exists(_.name == colName) || df.schema(colName).dataType.simpleString != colType.simpleString)
          throw exceptWithLog(DFINPUT_TEST_BADCOLS, s"Input DataFrame to Preprocess.process does not contain column $colName of type ${colType.simpleString}")
      }
    }

This is then implemented by:

object MyFunctionality extends DataFrameImplicits {
    def myfunc(df: DataFrame): DataFrame = {
        df.testInputFields( ??? )
        df.transform( ??? )
    }
}

Now, looking at more Scala code recently, I see that the "standard" way to include implicits is to define them in an object and import them

import com.package.implicits._

or something like that.

Is there any reason to convert my code to work that way? Is there any reason not to include implicit conversions in Scala traits?

kingledion
  • 2,263
  • 3
  • 25
  • 39
  • 2
    I think it depends on your preference, but having implicit in object or Trait will gave a slight difference because `Object` is Singleton while `traits` are not. – Rex Apr 05 '19 at 13:13
  • I would ask the opposite, why put _implicits_ in a trait? - Usually, this is done, just to create a aggregate object _(like `all`)_ that provide all the implicits at once. But, you always get them in scope by importing them from an object. – Luis Miguel Mejía Suárez Apr 05 '19 at 14:13
  • 1
    @LuisMiguelMejíaSuárez Once again, the reason can be implicit priorities. – Dmytro Mitin Apr 05 '19 at 14:22
  • 1
    @DmytroMitin Right, that is why I said _"usually"_. In any case, IMHO, implicit priorities are a complex use case. Which, I believe, are out of the scope of this question. But, is always worth mentioning it. – Luis Miguel Mejía Suárez Apr 05 '19 at 14:26

1 Answers1

2

From functionality standpoint there is no difference - implicits will behave in the same way.

Then why put extra restrictions on yourself? Importing an implicit from module is usually cleaner than extending a trait. If you don't want to flood your context with tons of implicits you can just import com.package.implicits.DataFrameTest. I usually have separate implicit objects for extended classes and implicit conversions.

Traits are usually used as type bounds or encapsulation for some functionality.

By the way, another common place for implicits is companion object. Then it gets automatically imported with your case class.

Andrey Patseev
  • 514
  • 4
  • 12
  • 4
    It's not true that "implicits will behave in the same way" (if there sre several implicits). If you import you define implicits of the same priority as local ones. If you extend you create low-priority implicits in comparison with local ones. – Dmytro Mitin Apr 05 '19 at 14:07