Reputation: 13
I want to overloading constructor of abstract class with specific type. For example, I have:
abstract class Polinom(v: T)
So, when I create Polinom[String]
, I want to call constructor(String)
, for Int I want to call constructor(Int)
. If T != String and T != Int
then I call constructor(T)
. In addition, for T == Int
my object must have method add
, for T == String
- reverse
, for T != String and T != Int
object doesn't has this methods. How can I do that?
Upvotes: 1
Views: 98
Reputation: 7604
You can use evidence parameters for this:
class Polinom[T](v: T) {
def add(i: Int)(implicit ev: T <:< Int) = v + i
def reverse(implicit ev: T <:< String): String = ev(v).reverse
}
val x = new Polinom(50)
val y = new Polinom("hello")
val z = new Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
If you want specific constructors for Int
and String
and can't get enough of that implicit evidence, you can do this:
def this(i: Int)(implicit ev: Int =:= T) = this({
//do special int stuff here
println("I am in the special int constructor")
ev(i)
})
def this(s: String)(implicit ev: String =:= T) = this({
//do special string stuff here
println("I am in the special string constructor")
ev(s)
})
EDIT: Apparently, the above didn't work for the OP, although it seems to be working for me, but you can always make a companion object and overload the apply method, as the other answers suggested.
class Polinom[T] private(v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = new Polinom(i)
def apply(s: String): Polinom[String] = new Polinom(s)
def apply[T](x: T): Polinom[T] = new Polinom(x)
}
val x = Polinom(50)
val y = Polinom("hello")
val z = Polinom(None)
println(x.add(3))
println(y.reverse)
//println(z.add(3)) <- Isn't allowed. Error: Cannot prove that None.type <:< Int
Link to Scastie (the demo's below)
<script src="https://scastie.scala-lang.org/j8fWjvVFS3CumCo3WbUgqQ.js"></script>
Upvotes: 4
Reputation: 27356
abstract class Polinom[T](v: T)
object Polinom {
def apply(i: Int): Polinom[Int] = constructor(i)
def apply(s: String): Polinom[String] = constructor(s)
def apply[T](v: T): Polinom[T] = constructor(v)
}
Polinom(0)
Polinom("hello")
Polinom(None)
For examples of the add
and reverse
methods, see the other answers to this question.
Upvotes: 1
Reputation: 22840
It would be better to model that as an ADT, something like:
sealed trait Polinom[T] {
def v: T
}
object Polinom {
final case class IntPolinom private[Polinom] (v: Int) extends Polinom[Int] {
def add(x: Int): IntPolinom =
this.copy(v = this.v + x)
}
final case class StrPolinom private[Polinom] (v: String) extends Polinom[String] {
def reverse: StrPolinom =
this.copy(v = this.v.reverse)
}
final case class GenericPolinom[T] private[Polinom] (v: T) extends Polinom[T]
def apply[T](v: Int): IntPolinom =
IntPolinom(v)
def apply[T](v: String): StrPolinom =
StrPolinom(v)
def apply[T](v: T): GenericPolinom[T] =
GenericPolinom(v)
}
Upvotes: 4