Scala inheritance default parameter in parent class
Asked Answered
I

2

9

I have an abstract class with a default value for its parameter. I don't want to have to reuse the default value in the constructor of all the possible implementations.

abstract class Place(val place: String = "World")
class Message(val message: String = "Hello", p: String) extends Place(p) {
    override def toString = s"$message $place"
}

What I want to get

new Message("Hi", "Universe") = "Hi Universe" // Ok
new Message("Hi") = "Hi World" // Doesn't work, second parameter is required
new Message() = "Hello World" // Doesn't work, second parameter is required

I considered using an auxiliary constructor omitting the second parameter, but it doesn't help since you can't call super constructors outside of the main constructor.

I want to know how to do it, or why it is not possible. I'm not looking for a workaround, like not using inheritance.

Issie answered 19/5, 2015 at 12:50 Comment(0)
B
1

You can reuse the default value in a more elegant way:

object Place {
  val defaultPlace = "World"
}
abstract class Place(val place: String = Place.defaultPlace)
class Message(val message: String = "Hello", p: String = Place.defaultPlace) extends Place(p) {
  override def toString = s"$message $place"
}
Bosomed answered 19/5, 2015 at 15:58 Comment(1)
works. not as encapsulated. Here you have 3 objects to juggle (object, abstract, and class). In particular not giving credit for object and abstract having same name. class Message has to know about object Place so using this requires more wiring, if that makes any sense. the abstract and concrete should handle it all.Stillwell
A
3

I'm afraid that is not possible. Quite simply, you ARE passing a value to Place constructor, so it wont use the default, whatever its value might be. If you don't mind having a var instead of a val, here is a variant that works for your 3 cases:

abstract class Place(var place: String = "World")
class Message(val message: String = "Hello") extends Place()
{
   def this(message: String, place: String) = {
      this(message)
      this.place = place
   }
   override def toString = s"$message $place"
}

Constructors in Scala are a little of a mess IMHO. Sometimes a better answer is just to use factory apply() methods on a companion object, which are more flexible.

Appalachian answered 19/5, 2015 at 13:7 Comment(0)
B
1

You can reuse the default value in a more elegant way:

object Place {
  val defaultPlace = "World"
}
abstract class Place(val place: String = Place.defaultPlace)
class Message(val message: String = "Hello", p: String = Place.defaultPlace) extends Place(p) {
  override def toString = s"$message $place"
}
Bosomed answered 19/5, 2015 at 15:58 Comment(1)
works. not as encapsulated. Here you have 3 objects to juggle (object, abstract, and class). In particular not giving credit for object and abstract having same name. class Message has to know about object Place so using this requires more wiring, if that makes any sense. the abstract and concrete should handle it all.Stillwell

© 2022 - 2024 — McMap. All rights reserved.