I have java interface
public interface LifecycleRegistryOwner extends LifecycleOwner {
#Override
LifecycleRegistry getLifecycle();
}
and Kotlin class that implements this interface, it would be super nice to have just
val lifecycle by lazy {
val result = LifecycleRegistry(this)
result
}
but compiler says it's an accidental override. is there way to tell it was made by intention?
my current implementation
class PartnerSettingsActivity :AppCompatActivity(),LifecycleRegistryOwner {
private val registry = LifecycleRegistry(this) //<< hate this class-wide val
override fun getLifecycle(): LifecycleRegistry = registry
You cannot tell Kotlin compiler to accept the risk of such "accidental override" because there would be conflicting constructs on the bytecode level. Neither you cannot use #JvmName to modify the name of field generated in bytecode because it does not work with delegates, and lazy is a delegate.
Related
In Scala official docs, it says that:
If this is the template of a trait then its mixin-evaluation consists
of an evaluation of the statement sequence statsstats.
If this is not a template of a trait, then its evaluation consists of
the following steps.
First, the superclass constructor sc is evaluated.
Then, all base classes in the template's linearization up to the template's
superclass denoted by sc are mixin-evaluated. Mixin-evaluation
happens in reverse order of occurrence in the linearization.
Finally, the statement sequence statsstats is evaluated.
I am wondering what the "mixin-evaluation" and "superclass constructor evaluation" mean here? Why is superclass constructor sc treated differently from traits mt1, mt2, mt3, etc.?
Well, this is one of those complicated things for which I don't think there is a good short answer unless you already know what the answer is. I think the short answer is that this is a result of the fact that Scala is compiled to the JVM bytecode and thus has to match restrictions of that target platform. Unfortunately I don't think this answer is clear so my real answer is going to be long.
Disclaimer: (a shameful self-promotion for the future readers): If you find this quite long answer useful, you might also take a look at my another long answer to another question by Lifu Huang on a similar topic.
Disclaimer: Java code in the translation examples is provided solely for illustrative purpose. They are inspired by what the Scala compiler actually does but don't match the "real thing" in many details. Moreover those examples are not guaranteed to work or compile. Unless explicitly mentioned otherwise I will use (simpler) code examples that are simplified versions of Scala 2.12/Java 8 translation rather than older (and more complicated) Scala/Java translations.
Some theory on mix-ins
Mixin is an idea in an object-oriented design to have some more or less encapsulated piece of logic that however doesn't make sense on its own and so it is added to some other classes. This is in a sense similar to multiple inheritance and multiple inheritance is actually the way this feature is designed in Scala.
If you want some real world examples of mix-ins in Scala, here are some:
Scala collection library implementation is based on mix-ins. If you look at definition of something like scala.collection.immutable.List you'll see a lot of mix-ins
sealed abstract class List[+A] extends AbstractSeq[A]
with LinearSeq[A]
with Product // this one is not a mix-in!
with GenericTraversableTemplate[A, List]
with LinearSeqOptimized[A, List[A]] {
In this example mix-ins are used to share implementation of advanced methods via core methods along the deep and wide Scala collections hierarchy.
Cake pattern used for dependency injection is based on mix-ins but this time the mixed-in logic typically doesn't make sense on its own at all.
What is important here is that in Scala you can mix-in both logic (methods) and data (fields).
Some theory on Java/JVM and multiple inheritance
"Naive" multiple inheritance as done in languages like C++ has an infamous Diamond problem. To fix it original design of Java didn't support multiple-inheritance of any logic or fields. You may "extend" exactly one base class (fully inheriting its behavior) and additionally you can "implement" many interfaces which means that the class claims to have all methods from the interface(s) but you can't have any real logic inherited from your base interface. The same restrictions existed in the JVM. 20 years later in Java 8 Default Methods were added. So now you can inherit some methods but still can't inherit any fields. This simplified implementation of mix-ins in Scala 2.12 at the price of requiring Java 8 as its target platform. Still interfaces can't have (non-static) fields and thus can't have constructors. This is one of the major reasons why the superclass constructor sc is treated differently from the traits mt1, mt2, mt3, etc.
Also it is important to note that Java was designed as a pretty safe language. Particularly it fights against "undefined behaviors" that might happen if you re-use some values that are just leftover (garbage) in the memory. So Java ensures that you can't access any fields of the base class until its constructor is called. This makes super call pretty much mandatory first line in any child constructor.
Scala and mix-ins (simple example)
So now imagine you are a designer of the Scala language and you want it to have mix-ins but your target platform (JVM) doesn't support them. What should you do? Obviously your compiler should be able to convert mix-ins into something that JVM supports. And here is a rough approximation of how it is done for a simple (and nonsense) example:
class Base(val baseValue: Int) {
}
trait TASimple {
val aValueNI: AtomicInteger
val aValueI: AtomicInteger = new AtomicInteger(0)
def aIncrementAndGetNI(): Int = aValueNI.incrementAndGet()
def aIncrementAndGetI(): Int = aValueI.incrementAndGet()
}
class SimpleChild(val childValue: Int, baseValue: Int) extends Base(baseValue) with TASimple {
override val aValueNI = new AtomicInteger(5)
}
So in words you have:
a base class Base with some field
a mix-in trait TASimple which contains 2 fields (one initial and one not initialized) and two methods
a child class SimpleChild
Since TASimple is more than just a declaration of methods, it can't be compiled to just a simple Java interface. It is actually compiled into something like this (in Java code):
public abstract interface TASimple
{
abstract void TASimple_setter_aValueI(AtomicInteger param);
abstract AtomicInteger aValueNI();
abstract AtomicInteger aValueI();
default int aIncrementAndGetNI() { return aValueNI().incrementAndGet(); }
default int aIncrementAndGetI() { return aValueI().incrementAndGet(); }
public static void init(TASimple $this)
{
$this.TASimple_setter_aValueI(new AtomicInteger(0));
}
}
public class SimpleChild extends Base implements TASimple
{
private final int childValue;
private final AtomicInteger aValueNI;
private final AtomicInteger aValueI;
public AtomicInteger aValueI() { return this.aValueI; }
public void TASimple_setter_aValueI(AtomicInteger param) { this.aValueI = param; }
public int childValue() { return this.childValue; }
public AtomicInteger aValueNI() { return this.aValueNI; }
public SimpleChild(int childValue, int baseValue)
{
super(baseValue);
TASimple.init(this);
this.aValueNI = new AtomicInteger(5);
}
}
So what TASimple contains and how it is translated (to Java 8):
aValueNI and aValueI as a part of val declarations. Those must be implemented by SimpleChild backing them with some fields (no tricks whatsoever).
aIncrementAndGetNI and aIncrementAndGetI methods with some logic. Those methods can be inherited by SimpleChild and will work basing on the aValueNI and aValueI methods.
A piece of logic that initializes aValueI. If TASimple was a class, it would have a constructor and this logic might have been there. However TASimple is translated to an interface. Thus that "constructor" piece of logic is moved to a static void init(TASimple $this) method and that init is called from the SimpleChild constructor. Note that Java spec enforces that the super call (i.e. the constructor of the base class) must be called before it.
The logic in the item #3 is what stands behind
First, the superclass constructor sc is evaluated.
Then, all base classes in the template's linearization up to the template's superclass denoted by sc are mixin-evaluated
Again this is the logic enforce by the JVM itself: you first have to call the base constructor and only then you can (and should) call all the other simulated "constructors" of all mix-ins.
Side note (Scala pre-2.12/Java pre-8)
Before Java 8 and default methods translation would be even more complicated. TASimple would be translated into an interface and class such as
public abstract interface TASimple
{
public abstract void TASimple_setter_aValueI(AtomicInteger param);
public abstract AtomicInteger aValueNI();
public abstract AtomicInteger aValueI();
public abstract int aIncrementAndGetNI();
public abstract int aIncrementAndGetI();
}
public abstract class TASimpleImpl
{
public static int aIncrementAndGetNI(TASimple $this) { return $this.aValueNI().incrementAndGet(); }
public static int aIncrementAndGetI(TASimple $this) { return $this.aValueI().incrementAndGet(); }
public static void init(TASimple $this)
{
$this.TASimple_setter_aValueI(new AtomicInteger(0));
}
}
public class SimpleChild extends Base implements TASimple
{
private final int childValue;
private final AtomicInteger aValueNI;
private final AtomicInteger aValueI;
public AtomicInteger aValueI() { return this.aValueI; }
public void TASimple_setter_aValueI(AtomicInteger param) { this.aValueI = param; }
public int aIncrementAndGetNI() { return TASimpleImpl.aIncrementAndGetNI(this); }
public int aIncrementAndGetI() { return TASimpleImpl.aIncrementAndGetI(this); }
public int childValue() { return this.childValue; }
public AtomicInteger aValueNI() { return this.aValueNI; }
public SimpleChild(int childValue, int baseValue)
{
super(baseValue);
TASimpleImpl.init(this);
this.aValueNI = new AtomicInteger(5);
}
}
Note how now implementations of aIncrementAndGetNI and aIncrementAndGetI are moved to some static methods that take explicit $this as a parameter.
Scala and mix-ins #2 (complicated example)
Example in the previous section illustrated some of the ideas but not all of them. For a more detailed illustration a more complicated example is required.
Mixin-evaluation happens in reverse order of occurrence in the linearization.
This part is relevant when you have several mix-ins and especially in the case of the diamond problem. Consider following example:
trait TA {
val aValueNI0: AtomicInteger
val aValueNI1: AtomicInteger
val aValueNI2: AtomicInteger
val aValueNI12: AtomicInteger
val aValueI: AtomicInteger = new AtomicInteger(0)
def aIncrementAndGetNI0(): Int = aValueNI0.incrementAndGet()
def aIncrementAndGetNI1(): Int = aValueNI1.incrementAndGet()
def aIncrementAndGetNI2(): Int = aValueNI2.incrementAndGet()
def aIncrementAndGetNI12(): Int = aValueNI12.incrementAndGet()
def aIncrementAndGetI(): Int = aValueI.incrementAndGet()
}
trait TB1 extends TA {
val b1ValueNI: AtomicInteger
val b1ValueI: AtomicInteger = new AtomicInteger(1)
override val aValueNI1: AtomicInteger = new AtomicInteger(11)
override val aValueNI12: AtomicInteger = new AtomicInteger(111)
def b1IncrementAndGetNI(): Int = b1ValueNI.incrementAndGet()
def b1IncrementAndGetI(): Int = b1ValueI.incrementAndGet()
}
trait TB2 extends TA {
val b2ValueNI: AtomicInteger
val b2ValueI: AtomicInteger = new AtomicInteger(2)
override val aValueNI2: AtomicInteger = new AtomicInteger(22)
override val aValueNI12: AtomicInteger = new AtomicInteger(222)
def b2IncrementAndGetNI(): Int = b2ValueNI.incrementAndGet()
def b2IncrementAndGetI(): Int = b2ValueI.incrementAndGet()
}
class Base(val baseValue: Int) {
}
class ComplicatedChild(val childValue: Int, baseValue: Int) extends Base(baseValue) with TB1 with TB2 {
override val aValueNI0 = new AtomicInteger(5)
override val b1ValueNI = new AtomicInteger(6)
override val b2ValueNI = new AtomicInteger(7)
}
What is interesting here is that ComplicatedChild inherits from TA in two ways: via TB1 and TB2. Moreover both TB1 and TB2 define some initialization of aValueNI12 but with different values. First of all it should be mentioned that ComplicatedChild will have only one copy of fields for each val defined in TA. But then what would happen if you try this:
val cc = new inheritance.ComplicatedChild(42, 12345)
println(cc.aIncrementAndGetNI12())
Which value (TB1 or TB2) would win? And will the behavior be deterministic at all? The answer to the last question is - yes, the behavior will be deterministic both between runs and between compilations. This is achieved via so called "traits linearization" which is an entirely different topic. In short the Scala compiler sorts all the inherited (directly and indirectly) traits in some fixed defined order such that it manifests some good behaviors (such as the parent trait is always after its child trait in the list). So going back to the quote:
Mixin-evaluation happens in reverse order of occurrence in the linearization.
This traits linearization order ensures
That all "base" fields are already initialized by the corresponding parent (simulated) constructors by the time the simulated constructor for some trait is called.
Order of the simulated constructors calls is fixed so behavior is deterministic.
In this particular case the linearization order will be ComplicatedChild > TB2 > TB1 > TA > Base. It means that ComplicatedChild constructor is actually translated into something like:
public ComplicatedChild(int childValue, int baseValue)
{
super(baseValue);
TA.init(this);
TB1.init(this);
TB2.init(this);
this.aValueNI0 = new AtomicInteger(5);
this.b1ValueNI = new AtomicInteger(6);
this.b2ValueNI = new AtomicInteger(7);
}
and so aValueNI12 will be initialized by TB2 (which will overwrite the value set by the TB1 "constructor").
Hope this clarifies a bit what's going on and why. Let me know if something is not clear.
Update (answer to comment)
The spec says
Then, all base classes in the template's linearization up to the template's superclass denoted by scsc are mixin-evaluated. Mixin-evaluation happens in reverse order of occurrence in the linearization.
what does the “up to” precisely mean here?
Let's extend the "simple" example adding one more base trait as following:
trait TX0 {
val xValueI: AtomicInteger = new AtomicInteger(-1)
}
class Base(val baseValue: Int) extends TX0 {
}
trait TASimple extends TX0 {
val aValueNI: AtomicInteger
val aValueI: AtomicInteger = new AtomicInteger(0)
def aIncrementAndGetNI(): Int = aValueNI.incrementAndGet()
def aIncrementAndGetI(): Int = aValueI.incrementAndGet()
}
class SimpleChild(val childValue: Int, baseValue: Int) extends Base(baseValue) with TASimple {
override val aValueNI = new AtomicInteger(5)
}
Note how here TX0 is inherited by both BaseClass and TASimple. In this case I expect linearization to produce the following order SimpleChild > TASimple > Base > TX0 > Any. I interpret that sentence as following: in this case the constructor of the SimpleChild will not call the "simulated" constructor of the TX0 because it comes in the order after the Base (= sc). I think the logic for this behavior is obvious: from the point of view of the SimpleChild constructor the "simulated" constructor of the TX0 should have already been called by the Base constructor, moreover Base might have updated results of that call so calling the "simulated" constructor of the TX0 second time might actually break the Base.
I think this could apply to both Java and Scala, but - a week in to learning Scala so trying that out. I have this:
class myBaseClass {
private var member: Int = 100
def doStuff(): Unit ={
checkMember()
alterMember(5)
}
private[this] def checkMember(): Unit = {
//throws exception if member < 0
}
private[this] def alterMember(i : Int): Unit = {
member -= i
}
}
And then I have a class which inherits the lot, overriding just one method as to call alterMember with a different value:
class mySubClass extends myBaseClass {
override def doStuff(): Unit ={
checkMember() // gives compiler error
alterMember(10) // gives compiler error AND IntelliJ says "alterMember inaccessible from this place"
}
}
checkMember() and alterMember are acting like private getters and setters. (I do only want doStuff to be able to change member , and are both inherited. WRONG - IGNORE THIS I don't understand why mySubClass is clearly able to access the private member as checkMember is just fine, but it seems it cannot alter it. Why would there be this variance? IGNORE UP TO HERE
Erasing the [this] makes no difference, but making alterMember public "fixes" it - but gives a level of access to member that I do not want.
The answer here, based on #MuratMustafin 's suggestion is to make the member and the two private methods protected.
What was also throwing, was that I needed to compile myBaseClass before attempting to compile mySubClass , otherwise it will say mySubClass cannot find those protected methods. Perhaps it's something with the Scala compiler that differs from the Java compiler in that it won't automatically know to compile them all, or compile them in order.
Could someone explain why scala would allow a public variable, to satisfy the implementation of an abstract declared Protected item? My first assumption is that the compiler would complain, but I created a small test to see if this worked, and to my surprise it does. Is there an advantage to this? (perhaps this is normal in OOP?) Any methods to avoid the accidental pitfall?
object NameConflict extends App {
abstract class A {
protected[this] var name:String
def speak = println(name)
}
class B(var name:String) extends A { //notice we've declared a public var
}
val t = new B("Tim")
t.speak
println(t.name) // name is exposed now?
}
It's normal and as in Java. Sometimes it's desirable to increase the visibility of a member.
You can't do it the other way around and turn down visibility in a subclass, because the member can by definition be accessed through the supertype.
If invoking a method has terrible consequences, keep the method private and use a template method that can be overridden; the default implementation would invoke the dangerous method.
abstract class A {
private[this] def dangerous = ???
final protected def process: Int = {
dangerous
template
}
protected def template: Int = ???
}
class B extends A {
override def template = 5
}
In Java I would write logger.getLogger(NameOfClass.class). How to write the same in Scala?
You could try:
logger.getLogger(getClass())
or:
logger.getLogger(classOf[NameOfClass])
As a side note, ScalaLogging provides a nice and easy way to use a logger with the class name but without all of the boilerplate like normal java. You get a logger in your class setup properly and all you have to do is extend a trait Logging:
class MyClass extends Logging {
logger.debug("This is very convenient ;-)")
}
Don't forget to define the logger on the singleton companion object:
object MyClass {
// Commons logging
private val clLogger = LogFactory.getLog(getClass())
// java.util.logging
private val juLogger = Logger.getLogger(getClass().toString)
}
class MyClass {
import MyClass._
...
}
The reason one should do this is that if you place the field on the class it's an instance field which goes back to the logger factory on every new instance of an object of that class. This can be unnecessary/unacceptable performance for some classes.
Scala's separation of the class (static) fields and instance fields, in this case, makes this much more arduous than would be done with Java. One of those cases where Scala doesn't have all the advantages:
class MyClass {
// Commons logging
private static final Log clLogger = LogFactory.getLog(MyClass.class)
// java.util.logging
private static final Logger juLogger = Logger.getLogger(MyClass.class.toString)
...
}
I'm currently constructing loggers (with configgy) like this:
class MyClass {
private val log = Logger.get(classOf[MyClass])
}
I would like to avoid repeating "MyClass" as in classOf[MyClass] (for example I want to quickly copy paste the log definition line, without smart IDE expanding the template with the class name), but I don't want to use the dynamic class of the current object, like:
class MyClass {
private val log = Logger.get(this.getClass)
}
EDIT: because this way instances of subclasses will have the subclass class object passed to the parent logger:
class MyClass {
private val log = Logger.get(this.getClass)
def doit = log.info("doing")
}
class SubClass extends MyClass {
}
new SubClass().doit
will use the logger configured for SubClass, not MyClass as I want.
Is there a way to have some fixed expression which somehow yields the class which is being defined at that point?
The short answer is that Scala doesn't have a way to do that. The long answer is that you can do it, but it's an ugly hack. The hack is to use the fact that exception stack traces include the name of the static class definition where the stack trace was created. Parse and tada. But, seriously, don't do this. Or, if you do, move it to a mixin trait and modify the parsing bit to pull the class name from the appropriate spot in the trace. Also, I've only tested this in some fairly limited conditions: no guarantee that it will work everywhere.
class MyClass {
private val log = Logger get (Class forName (
new RuntimeException().getStackTrace.apply(0).toString takeWhile
(_ != '(') split "\\." dropRight 1 mkString "."))
def doit = log.info("doing")
}
Surely you can just use the protected access modifier and access it directly?
class MyClass {
protected val log = Logger.get(classOf[MyClass])
}
class SubClass extends MyClass {
}
new SubClass().doit