Scala: Let trait depend on other trait - scala

I want to write a family of traits whose methods should log something and a Logger trait that should be implemented in concrete Loggers and it should only be possible to mix in the above traits when a Logger is mixed in as well. I only know that a trait can depend on a class, i.e. it can only be mixed into classes who have this class as super type. What can I do?

It sounds like you need self types e.g.
trait Logger {
def log(msg: String): Unit
}
trait ConsoleLogger extends Logger {
def log(msg: String): Unit = { println(msg) }
}
trait NeedsLogger { self: Logger =>
def doSomething(): Unit = {
self.log("about to do something...")
self.log("it worked!")
}
}
object Test extends NeedsLogger with ConsoleLogger {
}
Test.doSomething()

Related

Unable to extend type bounds in scala for implementations

I want to define an abstract variable with type bound in trait and implement in the respective extended class. Something similar to this
trait Animal {
def makeSound(): Unit
}
class Lion extends Animal {
override def makeSound(): Unit = println("Roar")
def scarySound(): Unit = println("Rooooaaarrrrr")
}
trait AnimalCostume {
val animal: _ <: Animal
def locate(): Unit = {
animal.makeSound()
}
}
class LionCostume extends AnimalCostume {
override val animal = new Lion()
def scareEveryOne(): Unit = animal.scarySound()
}
The code is not compiling with the following exception
unbound wildcard type
val animal: _ <: Animal
Can you help in understanding how do I achieve something like this and why it is failing with error that type is not bounded if I have explicitly defined the upper bound here

Stack Modification Traits in Scala Not Working

Scala Compiler giving error where trying to run following program.
Error:(19, 8) class Logging inherits conflicting members:
method log in trait TimestampLogger of type (msg: String)Unit and
method log in trait ShortLogger of type (msg: String)Unit
(Note: this can be resolved by declaring an override in class Logging.)
class Logging extends TimestampLogger with ShortLogger
^
trait ShortLogger {
def log (msg: String) {println(msg)}
trait TimestampLogger {
def log (msg: String) {
println("We are in Timestamp Logger")
println(new java.util.Date() )
}
}
class Logging extends TimestampLogger with ShortLogger
val a = new Logging
a.log("Log Message")
Why Stackable Modification in scala traits not suggesting the correct log method?
Why are we getting compilation error?
The error here is as message says lack of overrides.
You cannot have 2 different implementations of a method with the same signature. You have to resolve it. With traits you can have one implementation override another - this is actually required to perform trait linearization. But to be able to override you have to prove that overrides are about the same method. One way to fix it is to let methods override some base member. It always picks the "last" implementation.
trait Logger { def log(msg: String): Unit = () }
trait ShortLogger extends Logger {
override def log(msg: String) = println(msg)
}
trait TimestampLogger extends Logger {
override def log(msg: String): Unit = {
println("We are in Timestamp Logger")
println(new java.util.Date() )
}
}
// last override "wins" => ShortLogger implementation will be used
class Logging1 extends TimestampLogger with ShortLogger
// last override "wins" => TimestampLogger implementation will be used
class Logging2 extends ShortLogger with TimestampLogger
If you don't want to use last-wins, you have to reimplement the method in the place where they are conflicting:
class Logging extends TimestampLogger with ShortLogger {
override def log(msg: String) = ...
}
If you wanted to have both functionalities you would have to use a former approach + super
trait Logger { def log(msg: String): Unit = () }
trait ShortLogger extends Logger {
override def log(msg: String) = {
super.log(msg)
println(msg)
}
}
trait TimestampLogger extends Logger {
override def log(msg: String): Unit = {
super.log(msg)
println("We are in Timestamp Logger")
println(new java.util.Date())
}
}
// both will perform both loggings, but in a different order
class Logging1 extends TimestampLogger with ShortLogger
class Logging2 extends ShortLogger with TimestampLogger

Using structural types as "trait argument"

I'm building my code using traits as modules in a way that I can plug them interchangeably and as needed, something like the following example:
trait Module1 { def method1 = "method1" }
trait Module2 { def method2 = "method2" }
abstract class BaseClass {
def doWork: Unit
}
class ClassImpl extends BaseClass with Module1 with Module2 {
def doWork: Unit = {
println(method1)
println(method2)
}
}
However, some of my modules depend on some configuration variables (user-defined, runtime arguments), something I would pass as constructor parameters if they were classes. As traits do not accept parameters my idea for this was by using structural types:
trait Module1 {
this: {
val config1: Int
val config2: Int
} =>
def method1 = s"method1 c1=$config1 c2=$config2"
}
trait Module2 { def method2 = "method2" }
abstract class BaseClass {
def doWork: Unit
}
case class Config(c1: Int, c2: Int)
class ClassImpl(config: Config) extends BaseClass with Module1 with Module2 {
protected val config1 = config.c1
protected val config2 = config.c2
def doWork: Unit = {
println(method1)
println(method2)
}
}
Is it a good strategy for configuring my modules or there is something better?
Structural types involves reflection and are there is a better solution indeed, consider the following example:
trait Module[F,S] { this: Config[F,S] =>
def method = s"method1 c1=$config1 c2=$config2"
}
trait Config[F,S] {
def config1: F
def config2: S
}
case class DefaultConfig[T,S](config1: T, config2: S) extends Config[T,S]
case class ConfigCls(c1: Int, c2: Int)
class ClassImpl(config: ConfigCls) extends DefaultConfig(config.c1, config.c2) with Module[Int,Int] {
def doWork(): Unit = {
println(method)
}
}
This way you avoid using structural types, doing basically the same thing as in your original post.

Referencing the parent class inside a Trait

I have a class that extends a Trait and I want to write Traits that can mix in with the class and override some of the methods.
The trait that my class is extending looks like this
trait CharSource {
def source: Iterator[Char]
def words: Iterator[String] = {
while(source.hasNext){
//Logic to get the next word from a Char Iterator
}
}
final def chars: Iterator[Char] = words.toString().toIterator
}
The class that extends CharSource
class IteratorDocumentSource(iterator: Iterator[Char]) extends CharSource {
def source = iterator
}
Now I want to write a trait to override the source def in IteratorDocutmentSource for some special behavior
trait PunctuationRemover extends Transformer {self: CharSource =>
override
/** Character source. Overriding should be in terms of `super.source` for
stackability. */
abstract val source: Iterator[Char] = {
super.source
//additional logic ...
}
}
The transformer trait that PunctioationRemover extends
trait Transformer {self: CharSource =>
protected def source: Iterator[Char]
def words: Iterator[String]
}
I get an error when making this call
new IteratorDocumentSource("Hello World!".iterator) with PunctuationRemover
Error:
An exception or error caused a run to abort:
SampleSuite$$anonfun$2$$anon$3.document$PunctuationRemover$$super$source()Lscala/collection/Iterator;
java.lang.AbstractMethodError:
SampleSuite$$anonfun$2$$anon$3.document$PunctuationRemover$$super$source()Lscala/collection/Iterator;
I referenced this post but I think my situation is a little different
Can I override a scala class method with a method from a trait?

Scala trait runtime class from type parameter

I have a scala trait [this trait does not compile]
trait MyTrait[T <: Enum] {
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, classOf[T])
}
}
And a Java class
public class MyJavaClass {
public static <T extends Enum> T staticMethod(String name, Class<T> c) {
return (T) T.valueOf(c, name);
}
}
How can I make the trait valid scala? What I'm currently doing is adding a Class[T] field like this
trait MyTrait[T <: Enum] {
val t: Class[T]
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, t)
}
}
but I don't like having to add a t field to all classes that want to use this trait.
Nice and common way of working around type erasure in Scala is to use ClassTags.
They're usually passed as implicit parameters. Unfortunately, traits can't take constructor parameters, so the best that we can have is:
import scala.reflect.ClassTag
trait MyTrait[T <: Enum] {
val ttag: ClassTag[T]
def myMethod(name: String): T = {
MyJavaClass.staticMethod(name, ttag.runtimeClass.asInstanceOf[Class[T]])
}
}
Then, every class extending MyTrait must be defined like this:
class MyClass[T <: Enum](/*your params, if any*/)(implicit val ttag: ClassTag[T]) extends MyTrait[T] {
/*your class body*/
}
Then, if you have some concrete enum MyEnum, you can create instances of your class seamlessly:
new MyClass[MyEnum](/*your params, if any*/)