3

given two classes:

 abstract class ClassA(val argA:Int = 1) {
   def func1 {
     ... argA ... //some operations
     func2
   }
   def func2
 }

class ClassB extends ClassA {
   def func2 {
     ... argA ... //some operations
   }
}

val b = new ClassB
b.func1

How can I pass argA=3 while instantiating b? There will be dozens of child-classes like B, so it would be good if there were no need to rewrite "(val argA:Int = 1)" in every class definition. Even in this case, things would be somehow obscure.

The most similar question I have found is about getting, not setting the value: question

5 Answers 5

2

As you can see, there are several possible ways how to achieve what you asked for. However, it is not obvious which one is the best way, since that depends on what you'd like to put your emphasis on (conciseness, reuse, performance) and how your actual code looks. Some things worth having in mind are:


With solutions along the line of @maackle's, each instantiation of the form

val b = new ClassB { override val argA = 3 }

will result in an anonymous class class AnonSubB extends ClassB that is created behind the scenes. If you want to focus on conciseness, then this is probably the way to go, but the anonymous classes might slow down compilation if their number increases.


@paradigmatic's solution

class ClassB(i: Int) extends ClassA(i) { ... }
val cb = new ClassB(3)

is nearly as concise and does not result in anonymous classes, but has the disadvantage that the default value of argA as specified by ClassA is not reused (which it is in @maackle's solution). You could repeat the value, i.e., declare ClassB as

class ClassB(i: Int = 1) extends ClassA(i) { ... }

but this is error-prone, since you have to change the default value in various places, should it ever need to be changed.


I also like to offer a solution of my own, where the focus lies on reusing default values without creating anonymous classes, but which is less concise:

/* ClassA has a reusable (referenceable) default value */
abstract class ClassA(val argA: Int) {
  def this() = this(ClassA.defaultArgA)
}

object ClassA {
  val defaultArgA = 1
}

/* ClassB reuses ClassA's default value */
class ClassB(x: Int = ClassA.defaultArgA) extends ClassA(x)

/* ClassC has a local (non-referenceable) default value */
class ClassC(x: Int = 10) extends ClassA(x)

println(new ClassB(2).argA) // 2
println(new ClassB().argA)  // 1
println(new ClassC().argA)  // 10
Sign up to request clarification or add additional context in comments.

Comments

1

Override argA at instantiation:

val b = new ClassB {
    override val argA = 3
}

Based on what you wrote, that seems to be the most concise way to do what you want. Depending on your actual use though, you might find some less clunky way to instantiate your objects by defining some methods on a companion object.

Comments

1

Just pass it, in the class definition:

class ClassB( i: Int ) extends ClassA(i) { ... }

val cb = new ClassB( 3 )

Comments

0

Just pass the argument to ClassA:

class ClassB extends ClassA(3) { ... }

2 Comments

"How can I pass argA=3 while instantiating b", not extending. The default value should stay at 1.
val b = new ClassB will pass argA=3 while instantiating b. ClassB doesn't take args, according to your question. If you want that, you have to write class ClassB(argA: Int = 1) extends ClassA(argA). If you have a whole load of default params you might want to abstract them into a case class upon which you can change values using copy.
0
abstract class ClassA {
    val argA: Int = 1
    def func1() {
        println(argA)
    }
}

class ClassB extends ClassA {
    def func2() {
        println("B: %d" format argA)
    }
}

val b = new ClassB { override val argA = 3 }
b.func1()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.