Scala inheritance default parameter in parent class - scala

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.

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.

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"
}

Related

Modify constructor arguments before passing it to superclass constructor in Scala

I have a superclass:
class Filter(val param: ComplexFilterParams){
def this(config: String) = this(parseStrConfig(config))
And I need to create a subclass that gets a String argument and then parses it in another way and creates ComplexFilterParams.
Something like that:
class NewFilter(str:String) extends Filter {
Is there a way to do it?
I got one solution. But I think it's ugly. I create companion object, define there a convert method and do next:
class NewFilter(str:String) extends Filter(NewFilter.convert(str)) {
You can go mush easier with another apply implementation in companion object like:
class NewFilter(val param: ComplexFilterParams) extends Filter(param){
//other implementations
}
object NewFilter {
def apply(str: String) = new NewFilter(convert(str))
def convert(str: String): ComplexFilterParams = ...
}
val filter = NewFilter("config string")

Scala instantiate common val on two classes with same parent

I have two classes that extend the same trait :
trait Event {
val propertyCommon : String = ""
}
case class EventA(propertyA : String) extends Event
case class EventB(propertyB : String) extends Event
Now I instantiate my classes in a List :
myList : List[Event] = List(EventA("a"),EventB("b"))
What I want to do is to instantiate after the common property, as if there was a copy method in my trait :
myList.map(_.copy(propertyCommon = "Something"))
How could I do that ?
What you say you want to do is called a prototype pattern in OOP, and as far as I can tell it isn't supported out of the box in Scala (and I think anywhere else).
There are also a few problems:
propertyCommon is not set up using constructor, so each implementation that would have to set it, would most likely have to override it using anonymous class (but then, this property will not be a part of equals, hashcode, toString, derivation, etc)
Event doesn't define any interface that would allow updating it
The easiest (and safest) way I see to implement functionality you want, would be something like this:
trait Event {
val propertyCommon: String // will be set by implementing class
def clone(propertyCommon: String = this.propertyCommon): Event
}
// children define propertyCommon to match the interface
case class EventA(propertyA: String, propertyCommon: String = "") extends Event {
def clone(propertyCommon: String = this.propertyCommon): EventA = copy(propertyCommon)
}
case class EventB(propertyB: String, propertyCommon: String = "") extends Event {
def clone(propertyCommon: String = this.propertyCommon): EventB = copy(propertyCommon)
}
However, probably if we knew more about your problem we could provide some other, simpler solution.

Case classes with inheritance and default parameters

Is there an elegant way in Scala to use case classes (or case classish syntax) with inheritance and default constructor parameters? I kind of want to do this (without repeating the default parameters of the superclass):
abstract class SuperClazz(id: String = "")
case class SubClazz(name: String = "", size: Int = 0) extends SuperClazz
val sub = SubClazz(id = "123", size = 2)
I would say it's not possible to do without repeating parameters from super class. It is due to the fact that case classes are special type of scala classes. It is beacuse compiler implicitly generates companion extractor object with apply and unapply methods and in those methods it will be no parameter that is not specified in class parameters.
Consider this code snippet
abstract class SuperClazz(id: String = "")
class SubClazz(name: String,id: String) extends SuperClazz {
override def toString: String = "name: " + name + ",id: " + id
}
object SubClazz {
def apply(name: String = "", id: String = "") = new SubClazz(name, id)
}
It's shorter and simpler ( and little bit different regarding toString method ) version of what is being created when
case class SubClazz(name: String, id: String) extends SubClazz
is called.

Inherited variable doesn't like new values

Could someone explain me why:
abstract class Super(var title: String)
class Sub(title: String) extends Super(title) {
def test = println(title)
}
val s = new Sub("a")
s.test
s.title = "b"
s.test
prints:
a
a
instead of:
a
b
?
It's easy. You simply refers to constructor param, not the inherited variable. You may either rename constructor param, or refer to the var with this. prefix
class Sub(titleP: String) extends Super(titleP) {
def test = println(title)
}

Scala problem optional constructor

Imagine this simple piece of code:
class Constructor() {
var string: String = _
def this(s: String) = {this() ; string = s;}
def testMethod() {
println(string)
}
testMethod
}
object Appl {
def main(args: Array[String]): Unit = {
var constructor = new Constructor("calling elvis")
constructor = new Constructor()
}
}
The result is
null
null
I would like to be
calling elvis
null
How to achieve this? I cannot call the method testMethod after the object creation.
Mazi
Your test method is called in the main constructor first thing. There is no way another constructor might avoid it being called before its own code runs.
In your case, you should simply reverse which constructor does what. Have the main constructor have the string parameter, and the auxiliary one set it to null. Added gain, you can declare the var directly in the parameter list.
class Constructor(var s: String) {
def this() = this(null)
def testMethod() = println(s)
testMethod()
}
In general, the main constructor should be the more flexible one, typically assigning each field from a parameter. Scala syntax makes doing exactly that very easy. You can make that main constructor private if need be.
Edit: still simpler with default parameter
class Constructor(var s: String = null) {
def testMethod = println(s)
testMethod
}