i am quite new in Scala. Have class named 'Document' and a few classes, like 'Doc1' and 'Doc2' which are children of Document. So:
abstract class Document(id: Int, xmlString: String) {
// make some operations and create an instance of subtype
}
case class Doc1 extends Document {
// some subclass specific methods
}
case class Doc2 extends Document {
// some subclass specific methods
}
Would like to run Document constructor and as a result, create an instance of Doc1 or Doc2 conditionally due to passed paramethers. Shall i add some auxiliary constructors in 'Document' class?
Any idea welcome.
The best practice is to use companion object/singleton object:
abstract class Document { ... }
object Document {
def apply(docType: String) = {
if (docType == "doc1") {
Doc1()
} else {
Doc2()
}
}
}
and the usage of it:
val document1 = Document("doc1")
Of course, it's just a simple example - you can change the docType to sealed class and check the type by pattern matching.
Update - by #crater2150 comment - you can use the apply instead of different function name, so you will write Document("doc1") instead of Document.someFunctionName("doc1")
Related
Scala throws "reassignment to val" error for the following code.
abstract case class Gun(var bulletCount:Int)
class Pistol(bulletCount:Int) extends Gun(bulletCount){
def fire() { bulletCount=bulletCount-1 }
}
Anything I missed here?
For starters, you should consider case class as final, and not extend them.
Second, do not use var with case class, you should rather create a copy of a case class to get one of its field changed.
Third, if you want a common type, you can use a base trait.
All in one, here's what it could look like:
sealed trait Gun {
def bulletCount: Int
}
case class Pistol(bulletCount: Int) extends Gun {
def fire(): Pistol = copy(bulletCount=bulletCount)
}
You're referring to bulletCount field generated by Pistol primary constructor parameter. To set base class variable, you need to directly call field using super:
class Pistol(bulletCount: Int) extends Gun(bulletCount) {
def fire(): Unit = {
super.bulletCount = super.bulletCount - 1
}
}
Alternatively, you can label parameter-generated field with override var:
class Pistol(override var bulletCount: Int) extends Gun(bulletCount) {
def fire(): Unit = {
bulletCount = bulletCount - 1
}
}
On a side note, as Frederic A. suggested in his answer, you should avoid inheriting case classes. They are syntactic sugar, and code generation don't work over inheritance - you'll need to implement all the fancy stuff like apply or unapply methods in companion class all by yourself. Scala compiler team tried to support case class to case class inheritance, but discovered that it breaks structural equality and lots of other things.
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.
I have an object that contains one or more case classes and associated methods. I would like to reuse this case class within another object (which has similar characteristics as this object but also some differentiating methods).
private object abc {
/* ... */
case class xyz(..) { def someFunc(){} }
object xyz { def apply() {} }
}
private object extendabc {
// How to reuse case class xyz here?
}
If you want to just access you can use this kind of a code .
private object abc {
case class xyz() {
def someFunc(){}
}
object xyz { }
}
private object extendabc {
val a = new abc.xyz()
a.someFunc()
}
You need to call this way because xyz is a nested member of the object abc .
Look here.
Also please note you cannot define a apply method in the companion object of a case class as it provides the exact same apply() method (with the same signature.
In Scala, is it possible to call a member method without having to call an instance of itself?
For instance, having this class:
class Model {
def action(value : String) = {
// Do action
}
}
this object implementation works:
object MyModel extends Model {
this action "doSomething"
}
But I would like to do something like this:
object MyModel extends Model {
action "doSomething"
}
As one does with Java property files, since it's a neat way to define the state of an object.
I managed to define an alias for this:
def declare = this
but it's the same issue of having to use a word in front of the call to the member method.
Is there an option to do this?
Yes, but you have to use parentheses:
object MyModel extends Model {
action("doSomething")
}
See this answer for example for more detail about when parentheses can or cannot be omitted.
As a side note, you could also alias this as follows:
object MyModel extends Model { declare =>
declare action "doSomething"
}
This is often useful if you want to refer to a class's this from inside of a nested class—it's a bit less verbose than writing Outer.this.x as you would in Java.
I want to make a composition with two objects. I can do it with objects nesting:
object Composition {
object SomePartOfComposition {
// some body
}
}
But the body of SomePartOfComposition is such long, that I want it in a separate file. How can I do that?
// edit
I know, that I can use trait. But I want strict one to one relation - it is a singleton.
object Composition {
object SomePartOfComposition extends SomePartTrait
}
trait SomePartTrait{
//in it's own file
//implement the body here
}
You haven't specified why it matters that one object is nested in the other, so I assume that you just want the syntax to look like A.B. So:
//File A
object A {
val B = C
}
// File C
object C {
import A._
// All your code, written just like it was placed inside A
}
If this is not what you want, please edit the question to explain all the criteria.
You can have a strict one to one relationship when using traits by defining the self type of the trait to be the type of the object:
object Composition {
object SomePartOfComposition extends SomePartOfCompositionTrait
}
trait SomePartOfCompositionTrait {
this: Composition.SomePartOfComposition.type =>
// body
}