Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to make the subclass arguments available in the abstract class for pattern matching in scala?

I have a class and two case subclasses:

abstract class C
case class C1(left: C, right: C, weight: Int) extends C
case class C2(weight: Int) extends C

I want to implement something like the following:

def weight(t: C): Int = {
    t match {
      case c1: C1 => l.weight
      case c2: C2 => c2.left.weight + c1.right.weight //this line doesn't let the code compile
    }
  }

The above code does not compile. says left and right do not have attribute weight. I am seeing this because C does not have a weight defined for it. Only c1 and c2 do. However, the class instances that I pass to the weight function would be either c1 or c2 and would definitely have weight.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

It is actually a recursive weight summation on a tree that I can achieve with the following:

def weight(t: C): Int = {
    t match {
      case c1: C1 => l.weight
      case c2: C2 => weight(c2.left) + weight(c1.left)
    }
  }

But, I do not want to recurse and I do not think I should have to if the weight information is simply there available in the instance that I am passing in.

It is an assignment question that I am trying to solve and the signature of classes C, C1 and C2 are sacrosanct. I have tried modifying

abstract class C

to

abstract class C:
    val weight: Int = ???

However, this then starts raising issues with the weight variable in the C1 and C2 signatures and asks me to override it.

The one solution I tried and thought would work was creating a companion object:

abstract class CodeTree
object CodeTree:
  val weight: Int = ???
case class Fork(left: CodeTree, right: CodeTree, chars: List[Char], weight: Int) extends CodeTree
case class Leaf(char: Char, weight: Int) extends CodeTree

But I think the companion objects are not inherited by the subclasses

  • How do I achieve the desired outcome without having to recurse?
  • More broadly, How do I endow an abstract class with — this particular field would always be available in the subclasses that inherit from me and hence it should be available statically with me and not fail compilation?

>Solution :

You should add member weight: Int to C

abstract class C:
  def weight: Int
case class C1(left: C, right: C, weight: Int) extends C
case class C2(weight: Int) extends C

Then you can match typed patterns

def weight(t: C): Int =
  t match
    case c1: C1 => c1.left.weight + c1.right.weight
    case c2: C2 => c2.weight

or constructor patterns

def weight(t: C): Int = 
  t match 
    case C1(l, r, _) => l.weight + r.weight
    case C2(w) => w

Why do we have a need for separate case identifiers in case of type only matching in scala?

Normally abstract members are defs and overriden with def/val/lazy val (var if necessary) in implementations.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading