Overriding vals in Scala - scala

I have tried to override val in Scala as this:
trait T{
val str: String
}
sealed abstract class Test extends T{
val str: String = "str"
}
class Test1 extends Test{
val str = super.str + "test1" //super may not be used on value str
}
But this refused to compile. Why? I wanted to override value in the abstract class using the abstract class's value itself. How to do this?
In my particular case I cannot pass it as a class parameter.

Scala compiler does not allow to use super on a val. If you are not caring about re-evaluation, you can just use def instead.
trait T{
def str: String
}
sealed abstract class Test extends T{
def str: String = "str"
}
class Test1 extends Test{
def str = super.str + "test1" //super may not be used on value str
}
defined trait T
defined class Test
defined class Test1

If you do care about it avoiding repeated initialization, you can extract it into a method:
sealed abstract class Test extends T {
lazy val str: String = initStr
protected def initStr = "str"
}
class Test1 extends Test{
override protected def initStr = super.initStr + "test1"
}
You can also make str non-lazy, but it's all to easy to end up with initialization order problems that way.

Related

Case object extending trait

We can supply parameter to a class extending trait with the same name as an abstract method like
trait Trr{
def m: String
}
case class Trrrr(m: String) extends Trr //fine
This example compiles fine. But I tried to do something like that with case objects and failed:
trait Command{
def name: String
}
case object Unload("unld") extends Command //compile error
Is there a way to write this concisely while leaving Command a trait, not an abstract class with parameter? I mean not like that:
case object Unload extends Command {
override def name: String = "unld"
}
or
abstract class Command(name: String)
case object Unload extends Command("unld")
case object Unload extends Command { val name = "unld" }
Object don't have arguments, things won't get any shorted than the above...
You can instantiate the trait directly like so:
val newTrr = new Trr { val m = "example" }
At this point you can use the newTrr value just like any class instance...
println(newTrr.m)
which will print out: "example".

Scala - object extends abstract class and takes parameters

//File Animal.scala
abstract class Animal {
val name: String
def getSomething(tClass: TypeClass): String = {
tClass.tName.split('.').lift(0)
}
def apply(tClass: TypeClass): SomeOtherClassType = {
// something...
}
// File: DogSpike, this is used for some specific cases (overwrites
base class val)
object DogSpike extends Animal {
override val name: String = "Spike"
}
this call then works (calls apply)
myTransformation(() => DogSpike(this))
Now I would like to create a more generic object that one can pass arguments but I am unable to.
It would work to create a derived Object from Animal that takes one arguments and being able to use the apply call
object TheDog(name: String) extends Animal {
override val name: String = "Spike"
//...
}
not sure how to implicitly call Animal.apply for TheDog object where I could pass a parameter (name)
myTransformation(() => TheDog(this))
// also this seems to be incorrect "*Wrong top statement declaration*"
object TheDog(val n: String) extends Animal {
override val name: String = n
//...
}
As of *Wrong top statement declaration* (I can understand only this part of your question) - you can't have constructor in object as object is a singleton, so you should use a case class (ADT):
final case class TheDog(name: String) extends Animal
scala>TheDog("Spike")
res2_2: TheDog = TheDog("Spike")
val and companion object with apply is added automatically for case classes, so you don't need to define your own own apply in Animal. case class TheDog(val name: String) is same as case class TheDog(name: String).
I's also use traits instead of abstract class:
trait Animal {
val name: String
def getSomething: String = {
"Dog: " + name
}
}
I don't understand your TypeClass type, but if you really want type classes:
trait Animal {
def name: String
}
final case class TheDog(name: String) extends Animal
final case class TheCat(name: String) extends Animal
implicit class RichDog(dog: TheDog){
def getSomething: String = {
"Dog" + dog.name
}
}
implicit class RichCat(cat: TheCat){
def getSomething: String = {
"Cat: " + cat.name
}
}
scala> TheDog("Spike").getSomething
res4_5: String = "DogSpike"
scala> TheCat("Tom").getSomething
res4_6: String = "Cat: Tom"
About calling apply "implicitly", I don't know why would anyone need this, but:
trait AnimalFactory[A <: Animal] {
def apply(name: String)(implicit constructor: String => A) = constructor(name)
}
object TheeeDog extends AnimalFactory[TheDog]
implicit def createDog(name: String) = TheDog(name)
TheeeDog("Spike")
Of course you have to provide createDog and make it visible for a client, but it doesn't really make sense if you can just use ADTs and define additional required applys in companion object:
case class TheMouse(name: String)
object TheMouse{
def apply(isJerry: Boolean): TheMouse = if (isJerry) TheMouse("Jerry") else TheMouse("NotJerry")
}
TheMouse(true)
If you want to add some parameter to constructor, just add it:
class AnimalFactory(clazz: SomeClass){
def doSomething = clazz.name
def apply(name: String)
}
val dogFactory = new AnimalFactory(dogClassDescriptor)
val catFactory = new AnimalFactory(catClassDescriptor)
dogFactory("Spike")
catFactory("Tom")
You can even create a factory for factory (I wouldn't recommend - this solution already looks overcomplicated):
object AnimalFactory{ //please don't use classes for that - avoiding `new` is not their purpose
def apply(clazz: SomeClass) = new AnimalFactory(clazz)
}
val dogFactory = AnimalFactory(dogClassDescriptor)
//or even `val spike = AnimalFactory(dogClassDescriptor)("Spike")`
But still what's the point if you could just provide underlying clazz either as a member or just in a wrapper:
final case class ClazzWrapper[T <: Animal](clazz: SomeClass, animal: T)

Stub a val of a trait with scalamock

In the following (simplified) example, how can I stub the value of a trait that inherits fields from a class with scalamock?
trait MyTrait extends MyClass
class MyClass(val location: Location)
val expectedValue = ???
val dor: MyTrait = stub[MyTrait]
(dor.location.continuousFeatureValues).returns(expectedValue)
'location' is the parameter of MyClass or a data member of MyClass? Is it OK to change MyClass as:
class MyClass() {
val location: Location = new Location
}
If it is OK, you can override the location as a workaround:
//source code
class Location {
def continuousFeatureValues: String = "location"
}
class MyClass() {
val location: Location = new Location
}
class MyTrait extends MyClass
// test code
it should "mock" in {
val loc = mock[Location]
val dor: MyTrait = new MyTrait {override val location = loc}
(loc.continuousFeatureValues _).expects().returning("good")
dor.location.continuousFeatureValues shouldBe ("good")
}
I would refactor that code, as it is a bit of a dead end with a trait extending a class with a non-default constructor.
If you were to mock that class directly, you still could not define actions on location as it is a val, and those are immutable in Scala. Make it a def on MyTrait and have MyClass extend MyTrait and your design should be simpler to work with (and mock).

Use method to override itself in scala

Is there a way in scala to use a method m in the implementation of the method overriding the same method m?
As an example here is what I tried (note that toUpperCase is not implemented):
abstract class Person {
def greet: String
}
class EnglishMan extends Person {
abstract override def greet: String =
{
return "hello"
}
}
trait Angry extends Person {
abstract override def greet: String =
{
return toUpperCase(greet)
}
Is this what you want?
scala> trait Person { def greet: String }
defined trait Person
scala> class EnglishMan extends Person { def greet = "hello" }
defined class EnglishMan
scala> class Angry extends EnglishMan { override def greet = super.greet.toUpperCase }
defined class Angry
scala>
scala> new EnglishMan().greet
res3: String = hello
scala> new Angry().greet
res4: String = HELLO
Note that trait Person is completely irrelevant to this exercise. You can invoke your superclass' methods (even when overriding that very method), but you can't have 2 methods on the same scope with the same name (that would be ambiguous for the compiler).

Trouble with overriding a variable in abstract class

I'm new to scala and have the following question about overriding a variable in an abstract class.
abstract class ExampleClass1 {
val testVar = (i: String) => {
i + " A"
}
def exampleMethod1() = {
print testVar
}
}
object ExampleObject1 extends ExampleClass1 {
def getExampleValue() = {
exampleMethod1()
}
}
ExampleClass1 and ExampleObject1 are in one module. My module is calling ExampleObject1.getExampleValue. I want to change the behavior of testVar in ExampleClass1. Is it possible to do this without changing ExampleObjectt1?
Thank you
If you want to change a value after the class is instantiated, then you should use var instead of val, but without any further information it seems that there is a flaw in your design.
If you want to set the value of the given string on object creation, you can use something like this:
scala> abstract class ExampleClass1(val i: String)
defined class ExampleClass1
scala> object ExampleObject1 extends ExampleClass1("A")
defined object ExampleObject1
scala> ExampleObject1.i
res1: String = A
Or if you want to use given string as a parameter:
scala> abstract class ExampleClass2 {
| def test(i: String) = i + " A"
| }
defined class ExampleClass2
scala> object ExampleObject2 extends ExampleClass2
defined object ExampleObject2
scala> ExampleObject2.test("B")
res2: String = B A
What is your goal?