I'm using a Logging trait in my application and I'm curious whether it's possible to access a protected variable from the Logging trait.
This is what I have:
class MyClass extends ExternalTrait with Logging
trait ExternalTrait {
protected val protectedVar = "secret?"
}
trait Logging {
if(this.isInstanceOf[OtherTrait])
this.asInstanceOf[OtherTrait].protectedVar
}
but the access to the protected variable is restricted when accessing in this manner. Is there some other way to access the protectedVar from the Logging trait?
Many thanks.
If you definitely know that Logging later is mixed in to ExternalTrait you can place a self reference:
trait Logging { this: ExternalTrait =>
val value = protectedVar
}
Of course, if there can be logging traits which do not extend/mixin other traits self references are not suitable. In such a case I would subclass Logging to handle the different behavior.
trait Logging
trait StandAloneLogging extends Logging
trait BasedOnLogging extends Logging { this: ExternalTrait =>
val value = protectedVar
}
Related
I have a implicit class which requires a user database. I want to use self-type in implicit class so I can switch implementation of database in testing scope to the mocked version. How do I mix-in database provider in this case? For example, I want user of RuchUser to not worry about having to mix-in UserDatabaseProvider by providing default mix-in. So user can just do User("name").userContext and do the same at testing scope where I will provide default mix-in to use mocked database provider?
case class User(name: String)
object User {
implicit class RichUser(self: User) { this: UserDatabaseProvider =>
def userContext: String = this.getUserContext(self.name)
}
}
// Usage of Rich user should be below as I want to provide already mixed-in implicit
import User._
val context = User("name").uerContext
I think you are overcomplicating quite a bit.
case class User(name: String) {
def context()(implicit db: UserDatabaseProvider): UserContext = {
db.getUserContext(name)
}
}
I would go to further suggest the cake pattern may be more applicable here than using implicits.
class UserService extends UserDatabaseProvider {
def context(user: User): UserContext = getUserContext(user.name)
}
class TestUserService extends UserService with TestDatabase
Let "right-most wins" diamond resolution in Scala do the job for you.
Given a class like:
class MyClass {
protected object MyObj { ... }
}
is it possible to write a trait that will permit exposing MyObj. E.g. with inheritance I could do the following:
class TestMyClass extends MyClass {
val getMyObj = MyObj
}
but I want to do this via a trait, something like the following which doesn't typecheck:
trait ExposeMyObj {
val getMyObj = MyObj // super.MyObj/this.MyObj don't work
}
and use it like:
class TestMyClass extends ExposeMyObj
Is it possible to reproduce the functionality in TestMyClass into a trait to expose the protected object, and if so how?
If you know that your trait will always be mixed in to an instance of MyClass (or a subclass), you can enforce the expectation with a self-type, and then access the object:
trait ExposeMyObj {
self: MyClass =>
val getMyObj = MyObj
}
Edit: an example of using this trait:
class TestMyClass extends MyClass with ExposeMyObj
val test = new TestMyClass
test.getMyObj // accesses MyObj defined in MyClass.
Edit 2: attempting to address #jbrown's comment (re: testing queries within repos) - I would look at doing something like the following - first, in each repo's file, add a trait for each repo holding the queries for that repo:
trait UserQueries { // you could look at making this protected, if you like
protected def query1(param: String) = List(param) // very silly implementation, but hopefully enough to make the point
... // other queries
}
class UserRepo extends UserQueries // Has (internal) access to those queries
Then in the test class file for a given repo:
class UserQueriesTester extends UserQueries with ScalaTest { // or whatever test framework you are using
// (public) tests to run - eg:
def testQuery1 = query1("test") should be (List("test"))
}
I'm trying to design a small module system for my application such that I can do this:
new MyApplication extends Module1 with Module2 ... with ModuleN
In order to let my modules register themselves with the application, I also have:
trait ModuleRegistry {
def register(start: () => Unit) = // Stores start functions in a list
}
trait Module {
self: ModuleRegistry =>
self.register(start)
def start(): Unit
}
class Application extends ModuleRegistry {
}
trait Module1 extends Module {
...
}
The idea is that modules can register a function with the registry to be called when the application starts up. Unfortunately, the Scala compiler forces me to do this:
trait Module1 extends Module {
self: ModuleRegistry =>
}
meaning that all implementations of a module have to explicitly self-type themselves with the registry, when ideally they'd have no knowledge of it.
So my questions are:
Why does the compiler force me to re-specify this self-type on an extending trait? Ideally I don't even want the extending trait to 'see' this type, as it should be handled by the base Module trait. The 'concrete' module is meant to be implemented by 3rd parties, so exposing the registry to them seems kinda ugly.
Is there a better way to do what I'm trying to achieve in Scala so that modules can be freely mixed in?
This isn't a good use of the cake pattern, as you want all the modules to retain their own functionality (presumably), not mix and overwrite each other when mixed in. If you want the latter, you shouldn't: only with very careful design can this give predictable and sane results, and if third parties are supposed to provide the modules it's pretty much guaranteed that the design will not be that careful.
Instead, you should adhere to the "favor composition over inheritance" advice.
trait Module {
def start: Unit
}
trait Modular {
protected def moduleList: Seq[Module]
protected def register() = moduleList.map(m => m.start _)
}
class Application(modules: Module*) extends Modular {
protected def moduleList: Seq[Module] = modules // Fix varargs type
protected val registered = register()
}
object Module1 extends Module {
def start = println("One")
}
object Module2 extends Module {
def start = println("Two")
}
val app = new Application(Module1, Module2) {
registered.foreach(_())
}
// Prints "One", then "Two"
This is assuming a singleton is okay for a module. If you need a specific instance, you can either override apply (syntax is then Module1()) in the companion object, or add a builder trait that Module1 extends (e.g. trait ModuleBuilder { def module: Module }).
I have traits from two third party libraries that I'm trying to mix in to my own trait. They both define implicit vals named log.
However, they are of different types - one is an SLF4J Logger, the other is a Spray LoggingContext (which is really an Akka LoggingAdapter). In fact the second trait is from Spray, it's an HttpServer. (Not the most recent version you can find on Github which no longer has that val).
So, here's the code (library one renamed because it's proprietary, the Spray code snipped to show just relevant part):
object LibraryOneShim {
trait LibraryOne {
implicit val log: org.slf4j.Logger = ...
}
}
// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala
trait HttpService extends Directives {
val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter
}
trait MyTrait extends HttpService with LibraryOne {
val myRoute = ...
}
class MyActor extends Actor with MyTrait {
def receive = runRoute(myRoute)
}
This won't compile. The compiler complains:
error: overriding lazy value log in trait HttpService of type
java.lang.Object with spray.util.LoggingContext; lazy value log in
trait LibraryOne$class of type org.slf4j.Logger needs `override'
modifier trait DemoService extends HttpService with LibraryOne {
Is there any way I can mix in these two traits together?
As far as I can tell the only way is to create a CombinedLogger
class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter {
// proxy methods to the correct logger
}
If both loggers were declared as def you could use it like this:
override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log)
In this case it's tricky because they are defined as val which tell the Scala compiler they are a single value that will not change. And because of that it will not allow you to call super.log. So you would need to copy the logic of the overridden traits.
The other tricky part in this case is that you would need to proxy 50+ methods in the CombinedLogger.
I've looked at example of logging in Scala, and it usually looks like this:
import org.slf4j.LoggerFactory
trait Loggable {
private lazy val logger = LoggerFactory.getLogger(getClass)
protected def debug(msg: => AnyRef, t: => Throwable = null): Unit =
{...}
}
This seems independent of the concrete logging framework. While this does the job, it also introduces an extraneous lazy val in every instance that wants to do logging, which might well be every instance of the whole application. This seems much too heavy to me, in particular if you have many "small instances" of some specific type.
Is there a way of putting the logger in the object of the concrete class instead, just by using inheritance? If I have to explicitly declare the logger in the object of the class, and explicitly refer to it from the class/trait, then I have written almost as much code as if I had done no reuse at all.
Expressed in a non-logging specific context, the problem would be:
How do I declare in a trait that the implementing class must have a singleton object of type X, and that this singleton object must be accessible through method def x: X ?
I can't simply define an abstract method, because there could only be a single implementation in the class. I want that logging in a super-class gets me the super-class singleton, and logging in the sub-class gets me the sub-class singleton. Or put more simply, I want logging in Scala to work like traditional logging in Java, using static loggers specific to the class doing the logging. My current knowledge of Scala tells me that this is simply not possible without doing it exactly the same way you do in Java, without much if any benefits from using the "better" Scala.
Premature Optimization is the root of all evil
Let's be clear first about one thing: if your trait looks something like this:
trait Logger { lazy val log = Logger.getLogger }
Then what you have not done is as follows:
You have NOT created a logger instance per instance of your type
You have neither given yourself a memory nor a performance problem (unless you have)
What you have done is as follows:
You have an extra reference in each instance of your type
When you access the logger for the first time, you are probably doing some map lookup
Note that, even if you did create a separate logger for each instance of your type (which I frequently do, even if my program contains hundreds of thousands of these, so that I have very fine-grained control over my logging), you almost certainly still will neither have a performance nor a memory problem!
One "solution" is (of course), to make the companion object implement the logger interface:
object MyType extends Logger
class MyType {
import MyType._
log.info("Yay")
}
How do I declare in a trait that the
implementing class must have a
singleton object of type X, and that
this singleton object must be
accessible through method def x: X ?
Declare a trait that must be implemented by your companion objects.
trait Meta[Base] {
val logger = LoggerFactory.getLogger(getClass)
}
Create a base trait for your classes, sub-classes have to overwrite the meta method.
trait Base {
def meta: Meta[Base]
def logger = meta.logger
}
A class Whatever with a companion object:
object Whatever extends Meta[Base]
class Whatever extends Base {
def meta = Whatever
def doSomething = {
logger.log("oops")
}
}
In this way you only need to have a reference to the meta object.
We can use the Whatever class like this.
object Sample {
def main(args: Array[String]) {
val whatever = new Whatever
whatever.doSomething
}
}
I'm not sure I understand your question completely. So I apologize up front if this is not the answer you are looking for.
Define an object were you put your logger into, then create a companion trait.
object Loggable {
private val logger = "I'm a logger"
}
trait Loggable {
import Loggable._
def debug(msg: String) {
println(logger + ": " + msg)
}
}
So now you can use it like this:
scala> abstract class Abstraction
scala> class Implementation extends Abstraction with Loggable
scala> val test = new Implementation
scala> test.debug("error message")
I'm a logger: error message
Does this answer your question?
I think you cannot automatically get the corresponding singleton object of a class or require that such a singleton exists.
One reason is that you cannot know the type of the singleton before it is defined. Not sure, if this helps or if it is the best solution to your problem, but if you want to require some meta object to be defined with a specific trait, you could define something like:
trait HasSingleton[Traits] {
def meta: Traits
}
trait Log {
def classname: String
def log { println(classname) }
}
trait Debug {
def debug { print("Debug") }
}
class A extends HasSingleton[Log] {
def meta = A // Needs to be defined with a Singleton (or any object which inherits from Log}
def f {
meta.log
}
}
object A extends Log {
def classname = "A"
}
class B extends HasSingleton[Log with Debug] { // we want to use Log and Debug here
def meta = B
def g {
meta.log
meta.debug
}
}
object B extends Log with Debug {
def classname = "B"
}
(new A).f
// A
(new B).g
// B
// Debug