Scala instantiate common val on two classes with same parent - scala

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.

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 collection whose elements can construct sibling instances using named parameters and default values?

I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.

Is it possible to specify a static function in a Kotlin interface?

I want to do something like this:
interface Serializable<FromType, ToType> {
fun serialize(): ToType
companion object {
abstract fun deserialize(serialized: ToType): FromType
}
}
or even this would work for me:
interface Serializable<ToType> {
fun serialize(): ToType
constructor(serialized: ToType)
}
but neither compiles. Is there a syntax for this, or will I be forced to use make this an interface for a factory? Or is there another answer? 😮 That'd be neat!
Basically, nothing in a companion object can be abstract or open (and thus be overridden), and there's no way to require the implementations' companion objects to have a method or to define/require a constructor in an interface.
A possible solution for you is to separate these two functions into two interfaces:
interface Serializable<ToType> {
fun serialize(): ToType
}
interface Deserializer<FromType, ToType> {
fun deserialize(serialized: ToType): FromType
}
This way, you will be able to implement the first interface in a class and make its companion object implement the other one:
class C: Serializable<String> {
override fun serialize(): String = "..."
companion object : Deserializer<C, String> {
override fun deserialize(serialized: String): C = C()
}
}
Also, there's a severe limitation that only a single generic specialization of a type can be used as a supertype, so this model of serializing through the interface implementation may turn out not scalable enough, not allowing multiple implementations with different ToTypes.
For future uses, it's also possible to give the child class to a function as a receiver parameter:
val encodableClass = EncodableClass("Some Value")
//The encode function is accessed like a member function on an instance
val stringRepresentation = encodableClass.encode()
//The decode function is accessed statically
val decodedClass = EncodableClass.decode(stringRepresentation)
interface Encodable<T> {
fun T.encode(): String
fun decode(stringRepresentation: String): T
}
class EncodableClass(private val someValue: String) {
// This is the remaining awkwardness,
// you have to give the containing class as a Type Parameter
// to its own Companion Object
companion object : Encodable<EncodableClass> {
override fun EncodableClass.encode(): String {
//You can access (private) fields here
return "This is a string representation of the class with value: $someValue"
}
override fun decode(stringRepresentation: String): EncodableClass {
return EncodableClass(stringRepresentation)
}
}
}
//You also have to import the encode function separately:
// import codingProtocol.EncodableClass.Companion.encode
This is the more optimal use case for me. Instead of one function in the instanced object and the other in the companion object like your example, we move both functions to the companion object and extend the instance.

Scala - methods conditionally implemented in trait?

I am looking for the cleanest way to allow user to choose implementation of a method without repeating myself. in the situation below, each of the subclasses put together a greeting in XML with parameters from the specific class. thus the method toXML is declared abstract in the trait. What I want, however is to check if a _generalMessage was passed in in the construction of the class, and if so, use a general XML greeting common to all implementations of Greeting, e.g. <Message>_generalMessage</Message>. I know I can just pattern match on the existence of _generalMessage in each of the implementations of Greeting, but I am curious if there is a more elegant way.
trait Greeting {
protected var foo = //...
protected var _generalMessage: Option[Srting] = None
//...
//public API
def generalMessage: String = _generalMessage match {case Some(x) => x; case None =>""
def generalMessage_=(s: String) {_generalMessage = Some(s)}
protected def toXML: scala.xml.Node
}
class specificGreeting1 extends Greeting {
// class implementation
def toXML: scala.xml.Node = <//a detailed XML with values from class specificGreeting1>
}
// multiple other specificGreeting classes
Make toXML final, and define it in the base trait:
final def toXML = _generalMessage.fold(specific message) { m =>
<Message>m</Message>
}
Then define specificMessage in your subclasses to be what you currently have as toXML.

Is it possible to inherit auxiliary constructors in Scala?

I wonder if it is possible to inherit auxiliary constructors in Scala?
I tested this code, and it complained
temp.scala:18: error: too many arguments for constructor Child: ()this.Child
val a = new Child(42)
^
abstract class Father {
var value: Int = 0
protected def setValue(v: Int) = {
value = v
}
protected def this(v: Int) = {
this()
setValue(v)
}
}
class Child extends Father {
}
val a = new Child(42)
But if i put
protected def this(v: Int) = {
this()
setValue(v)
}
in the Child class, everything is all right.
Absolutely not, and your example demonstrates why. You've introduced a mutable variable value that may or may not be initialised - depending on the exact constructor used.
This is a potential source for a great many problems, and so Scala made the decision that all object creation should ultimately be directed via the primary constructor, this ensuring consistent initialisation.
If you want value to have a default value, then you can specify it as a default parameter (in 2.8+):
abstract class Father(val value : Int = 0)
or you can use the auxiluary constructor to achieve the same effect in Scala 2.7:
abstract class Father(val value : Int) {
def this() = this(0)
}
With Father defined in either of the above ways, the following definitions of child are both valid:
class Child(v:Int) extends Father(v)
class Child extends Father()
You can also make value a var if you absolutely have to, but I strongly advise against it.
If the semantics of value mean that it's valid to not be initialised, then the correct Scala idiom is to declare it as Option[Int]:
abstract class Father(val value : Option[Int] = Some(0))
Your Child constructor have no parameter and you are trying to instanciate it with one ! You have to declare a parameter in your Child constructor and then pass it to the Father class, for example:
class Child(v:Int) extends Father(v) {
}
val a = new Child(42)