Reputation: 7320
Trying to implement smart constructor using case classes. Managed to override the copy
method fine, and I presume the apply
in the companion object should have done the trick, but I hit a wall when trying to pass in a BigInt
. I tried putting in def apply(value: BigInt): Option[Natural]
but then scalac
complains about conflicting symbols.
import spire.math.Integral // companion object contains implicit Integral[BigInt]
case class Natural private (value: BigInt) {
def copy(value: BigInt = this.value): Option[Natural] =
Natural.apply(value)
}
object Natural {
def apply[A](x: A)(implicit A: Integral[A]): Option[Natural] =
if (A.isPositive(x)) Some(Natural(x))
else None
}
/** In Foo.scala */
Natural(5L) // Option[Natural] = Some(Natural(5))
Natural(BigInt(5L)) // constructor Natural in class Natural cannot be accessed in object Foo
Perhaps such a thing is not possible?
Upvotes: 1
Views: 2494
Reputation: 23046
Overloading is your problem here, as @jroesch points out in his answer.
A solution to this problem is to change the type of the argument of the private primary constructor so that the latter cannot conflict with the public factory method. There are various ways of doing that in Scala ... one might go like this,
case class Wrap[T](t: T) extends AnyVal
case class Natural private (value: Wrap[BigInt]) {
def copy(value: Wrap[BigInt] = this.value): Option[Natural] =
Natural(value.unwrap)
}
object Natural {
def apply[A](x: A)(implicit A: Integral[A]): Option[Natural] =
if (A.isPositive(x)) Some(Natural(Wrap(x)))
else None
}
Upvotes: 5
Reputation: 1260
I believe that the error you are encountering is because of method overloading. When creating a case class the compiler will generate a signature of:
def apply(x: T): T
for a case class T in it's companion object T. So when you are invoking the method, method selection picks the most specific signature first. It attempts to invoke Natural.apply(x: T): T
which I would hazard is also marked private transitively in the companion object. The conflicting symbols then becomes an issue, because it generates an apply(x: T): T
, and you are also defining an apply(x: T): T
.
Your best bet is using a plain Scala class, and manually implementing the extractor pattern, hash, equality, ect.
Upvotes: 2