How to indicate that the return type of an abstract method is a subclass type

How can I indicate in an abstract class that the return value of a method is of the same type as the specific class that is a member?

For instance:

abstract class Genotype {
  def makeRandom(): Genotype  // must return subclass type
  def mutate(): Genotype      // must return subclass type
}

I would like to say that whenever you call mutate()in a particular Genotype class, you will definitely get another instance of the same Genotype class.

I would prefer not to use the type parameter in the view Genotype[SpecificGenotype259], since this type parameter can propagate throughout the code (it is also redundant and confusing). I would prefer to identify specific classes of genotypes, ranging from different traits.

+4
source share
4 answers

:

trait GenotypeSystem {
  type Genotype <: GenotypeLike

  trait GenotypeLike {
    def makeRandom(): Genotype
    def mutate(): Genotype
  }
}

// Example implementation
object IntGenotypeSystem extends GenotypeSystem {
  case class Genotype(x: Int) extends GenotypeLike {
    def makeRandom() = copy(x = Random.nextInt(10))
    def mutate(): Genotype = copy(x = x + Random.nextInt(3) - 1)
  }
}

// Example abstract usage
def replicate(gs: GenotypeSystem)(g: gs.Genotype, n: Int): Seq[gs.Genotype] =
  Seq.fill(n)(g.mutate())

, , GenotypeSystem.

+1

F- :

abstract class Genotype[T <: Genotype[T]] {
  def makeRandom(): T  
  def mutate(): T      
}

class ConcreteGenotype extends Genotype[ConcreteGenotype] {
  def makeRandom(): ConcreteGenotype = ???
  def mutate(): ConcreteGenotype = ???
}
+5
abstract class Genotype {
  type T <: Genotype
  def makeRandom(): T  
  def mutate(): T      
}

Is this what you want?

+3
source

Maybe using covariant return types will work in your case?

abstract class Genotype {
  def makeRandom(): Genotype  // must return subclass type
  def mutate(): Genotype      // must return subclass type
}

class ConcreteGenotype(val a : Int) extends Genotype {
  override def makeRandom(): ConcreteGenotype = new ConcreteGenotype(a + 1)
  override def mutate(): ConcreteGenotype = new ConcreteGenotype(a + 2)
}

def useAbstractGenotype(g : Genotype) = g.mutate

val cg = new ConcreteGenotype(0) // cg: ConcreteGenotype = ConcreteGenotype@6c1c19c6
cg.mutate                        // res2: ConcreteGenotype = ConcreteGenotype@3fc1058a
useAbstractGenotype(cg)          // res3: Genotype = ConcreteGenotype@13515ded
0
source

Source: https://habr.com/ru/post/1540102/


All Articles