Scala class - required property - scala

I would like to define trait that has const property, for example:
trait InitialTest {
// property would be set here or somewhere else, let's call it typeNumber
override def toString = typeNumber.toString
}
then I would like to set this value for each implementation like:
case class InitialTest1 extends InitialTest {
// set value here like typeNumber = 4
}
For each toString function would use impelemetation from trait.
Do you know how can I acheive it?

The easiest way of achieving it, that I see is:
trait MyTrait {
val myProperty: X // abstract property
override def toString: String = myProperty.toString
}
It would force implementation of the property:
class Impl extends MyTrait {
val myProperty = new X // without that line it doesn't compile
}
From there on, one might complicate design further e.g. by splitting the trait with the property from the trait overriding toString with a cake pattern (though I'd be vary about it).

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

Reassignment to val error when var member of base class in scala

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.

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.

How do I access an overridden data member in Scala?

How do I call an overridden data member in Scala? Here's an example from a worksheet -- I'd like to do something like:
trait HasWings {
def fly() = println("I'm flying!")
val wingType = "Thin"
}
class Bee extends HasWings {
override def fly() = {
println("Buzzzz! Also... ")
super.fly() // we can do this...
}
override val wingType = "Translucent and " + super.wingType // ...but not this!
}
val bumble = new Bee()
bumble.fly()
println(s"${bumble.wingType}")
But I get the error, super may not be used on value wingType. How can I override the data member while still getting access to it? There are workarounds, like:
Not overriding the superclass value
Declaring the superclass value as a method
But I'm curious if I can have my override and my superclass data member access.
Thanks!
As the compiler tells you, scala does not allow to use super on a a val.
If you need this, you can refactor your code to use a def that is used to initialize the val. Then you can override the def instead:
trait HasWings {
def wingType0: String = "Thin"
val wingType = wingType0
}
class Bee extends HasWings {
override def wingType0 = "Translucent and " + super.wingType0
}
No, that is not possible at all.

Scala overriding a non-abstract def with a var

In Scala I can do this:
trait SomeTrait {
protected def foo: String
}
class Wibble extends SomeTrait {
protected var foo = "Hello"
}
But I cannot do the same thing where I provide a default definition for foo
trait SomeTrait {
protected def foo: String = "World"
}
class Wibble extends SomeTrait {
protected var foo = "Hello" //complains about lack of override modifier
override protected var foo = "Hello" //complains "method foo_ overrides nothing"
}
Why can't I do this?
EDIT: After a conversation on the scala-users mailing list, I have raised this in trac
In Scala, when you write a var foo, the Scala compiler automatically generates a setter (called foo_=) and a getter (called foo) for it, and sets the field as private (you'll see it as private if you decompile a class having 'public' Scala fields with javap). That's what the 'method foo_= overrides nothing' error means. In your trait you haven't defined a foo_= method, and for a public field setter and getters always come in pairs.
If you do not provide a default value in the trait (i.e. abstract method), then the override keyword is not necessary. Therefore, in your first example, the getter overrides the abstract method and the setter... it just is there. The compiler doesn't complain. But when you provide an actual implementation of the method in the trait, you need to specifically write the override keyword when overriding. When writing protected var foo, you haven't specified the override keyword for the getter and when writing override protected var foo, you have also indicated to the compiler that method foo_= is to be overridden, but the trait has no such method.
Also, logically you cannot really override a def with a var (considering a strict view of overriding, like in the previous paragraph). A def is logically a function (you give it some input, it produces an output). A var is similar to a no-arg function, but also supports setting its value to something else, an operation which is not supported by a function. Instead, if you would change it to a val, it would be OK. It's like a function that always produces the same (cached) result.
If you want to have similar behaviour to a var you could do something like this (by having explicit setter and getters):
class Wibble extends SomeTrait {
private var bar = "Hello"
override protected def foo = bar
protected def foo_=(v: String) { bar = v}
}
Now you can do anything you could do with a var :).
val x = new Wibble
println(x.foo) // yields "Hello"
x.foo = "Hello again"
println(x.foo) // yields "Hello again"