macwire icon indicating copy to clipboard operation
macwire copied to clipboard

Support companion object factory method

Open backuitist opened this issue 10 years ago • 5 comments

Sometimes you want to perform some validation before constructing an object. A good place for that is the method factory on the companion object:

class ParamsNeedValidation private(param1: Param1, param2: Param2)
object ParamsNeedValidation {
  def apply(param1: Param1, param2: Param2) : ParamsNeedValidation = {
     // validate param1 & param2
     new ParamsNeedValidation(param1, param2)
  }
}

When the primary constructor is found to be private, macwire could give the companion object a chance and IF it has a single apply method, try it. So we would end up with this:

lazy val pnv = wire[ParamsNeedValidation]

Turned into

lazy val pnv = ParamsNeedValidation(param1, param2)

If the companion object has more than one apply method, a compilation error is returned:

ParamsNeedValidation constructor is private and its companion object has more than one apply method:
- apply(param1, param2)
- apply(param3)

If the companion object has no apply method, then we would fail with the usual:

ParamsNeedValidation constructor is private

backuitist avatar Sep 06 '15 08:09 backuitist

This should also prove useful when you want to expose some of the inner parts of your object for testing:

package complex
// primary constructor is package private for testing as we want to play around with inner part 1 & 2
class ComplexService private[complex](innerPart1: IP1, innerPart2: IP2, other: Other) { /* ... */ }
object ComplexService {
   def apply(other: Other): ComplexService = {
      new ComplexService(new InnerPart1Impl, new InnerPart2Impl, other)
   }
}

backuitist avatar Sep 06 '15 09:09 backuitist

+1 A good rule might be to try to locate a unique publicly accessible way to constructor the object - either using a constructor or an apply method, with the appropriate return type

adamw avatar Sep 07 '15 07:09 adamw

Yep, secondary constructors could be evaluated too - as long as they are unique, as you said.

backuitist avatar Sep 07 '15 09:09 backuitist

TypeApi.companion does not seem to work? I've asked on scala-user (https://gitter.im/scala/scala/scala-user?at=55f6b30c8cc5f90a4fb6bf55) but so far no answer...

backuitist avatar Sep 16 '15 07:09 backuitist

Hmm no idea I've never tried it, but it sometimes does happen that things don't work in macro-land :)

adamw avatar Sep 16 '15 09:09 adamw