Scala inherit parameterized constructor

后端 未结 4 975
不知归路
不知归路 2021-02-02 09:53

I have an abstract base class with several optional parameters:

abstract case class Hypothesis(
    requirement: Boolean = false,
    onlyDays:   Seq[Int] = Nil,         


        
相关标签:
4条回答
  • 2021-02-02 10:30

    I've spend DAYS bashing my head on the desk trying to understand why named params were not going into an extended class.

    I tried traits, copy() you name it - me and the compiler were always at odds and when things did compile the values never got passed.

    So to be clear if you have class

    class A(someInt:Int = 0, someString: String ="xyz", someOtherString: String = "zyx")  
    

    And you want to extend it:

    class B extends A // does NOT compile 
    
    class B(someInt: Int, someString: String, someOtherString: String) extends A // compiles but does not work as expected 
    

    You would think that a call to B like so:

    case object X = B(someInt=4, someString="Boo", someOtherString="Who") 
    

    Would in fact either NOT compile (sadly it does) or actually work (it does NOT)

    Instead you need to create B as follows (yes this is a repeat of an above answer but it wasn't obvious at first when google led me here...)

    class B(someInt: Int, someString: String, someOtherString: String) extends A(someInt, someString, someOtherString) 
    

    and now

    case object X = B(someInt=4, someString="Boo", someOtherString="Who") 
    

    Both COMPILES and WORKS

    I have not yet worked out all the combinations and permutations of what/when and where you can put default values in the class B constructor but I'm pretty sure that defaults can be specified in the definition of class B with "expected" results.

    0 讨论(0)
  • 2021-02-02 10:39

    In my mind the policy of default values doesn't belong in the base class but should go on the concrete classes. I'd instead do the following:

    trait Hypothesis {
      def requirement: Boolean
      def onlyDays: Seq[Int]
      /* other common attributes as necessary */
    }
    
    case class SomeHypothesis(anotherArg: SomeType,
                              requirement: Boolean = false,
                              onlyDays: Seq[Int] = Nil)
      extends Hypothesis
    

    The case class fields of SomeHypothesis will fulfill the requirements of the Hypothesis trait.

    As others have said, you can still use an extractor for pattern matching on the common parts:

    object Hypothesis {
      def unapply(h: Hypothesis): (Boolean, Seq[Int]) = (h.requirement, h.onlyDays)
    }
    
    0 讨论(0)
  • 2021-02-02 10:43

    If Hypothesis is an abstract class, then I'd not have a constructor for it. I'd set those parameters as abstract attributes of the abstract class.

    But then, in this case you do need the override modifier.

    0 讨论(0)
  • 2021-02-02 10:53

    You can just use a dummy name in the inherited class:

    case class SomeHypothesis(anotherArg: SomeType, rq: Boolean = false, odays: Seq[Int] = Nil)
    extends Hypothesis(rq, odays)
    

    but you do have to repeat the default values. There is no need to override a val.

    EDIT:

    Note that your abstract class should not be a case class. Extending case classes is now deprecated. You should use an extractor for you abstract class instead:

    abstract class SomeHypothesis(val request: Boolean)
    
    object SomeHypothesis {
      def unapply(o: Any): Option[Boolean] = o match {
        case sh: SomeHypothesis => Some(sh.request)
        case _ => None
      }
    }
    
    0 讨论(0)
提交回复
热议问题