sealed class Genre{
sealed class Fiction : Genre(){
object Classics: Fiction()
object Fantasy: Fiction()
object ScienceFiction: Fiction()
}
sealed class NonFiction: Genre(){
object Biography: NonFiction()
object Business: NonFiction()
object Feminism: NonFiction()
object Politics: NonFiction()
object SelfHelp: NonFiction()
}
override fun toString(): String {
return this::javaClass.get().simpleName
}
I do not understand this context return this::javaClass...
When I press ctrl and hover over "this" it points to Genre class, This is confusing me.
I believe someone made a mistake in this code, making it a little confusing. What he/she really meant was:
this.javaClass.simpleName
Let's analyze it step by step:
this.javaClass creates Class object for provided this object. It could return e.g. Class<Fantasy>.
this::javaClass creates a property accessor for javaClass property of this object. It can be used later to access javaClass of this.
get() is called on property accessor to get the javaClass of this.
This way get() returned e.g. Class<Fantasy> and simpleName returned the name of a class.
I'm not sure if this explanation is at all possible to understand. But what is important is that this::javaClass.get() is the same as simply this.javaClass, probably done by a mistake.
Related
I would like to use Delegation on my Kotlin project, but I have a peculiar requirement. The delegation object itself should hold a reference to the parent object. To give you an example let's consider the following code:
interface MyInterface
class MyImpl(val a: MyTest?) : MyInterface
class MyTest : MyInterface by MyImpl(null)
What I'd like to do is replace null above with a this reference to MyTest object. But compiler doesn't let me with the error
'this' is not defined in this context
When I decompile the produced code, I get something like
public final class MyTest implements MyInterface
{
private final /* synthetic */ MyImpl $$delegate_0;
public MyTest() {
this.$$delegate_0 = new MyImpl(null);
}
}
which would seem perfectly legal, if I wanted to pass this instead of null when the delegate is initialized. But I can't figure how to do it. Is it a Kotlin's restriction or am I doing something wrong?
I know that I can bypass this restriction by using a var inside MyImpl and give a reference to parent.this at later time on my code. But this would mean that MyImpl will have a mutable reference of something that could be val instead, and I don't think this solution is elegant enough.
It means that, by the time of the base class constructor execution, the properties declared or overridden in the derived class are not yet initialized. If any of those properties are used in the base class initialization logic (either directly or indirectly, through another overridden open member implementation), it may lead to incorrect behavior or a runtime failure. When designing a base class, you should therefore avoid using open members in the constructors, property initializers, and init blocks.
I was studying Inheritence from Kotlin docs, and I got stuck here. There was another post which asked a question about this, but the answers were just what the docs said in a different way.
To be clear, I understood the data flow between constructors and inheritence. What I couldn't understand was how we can use an overridden property in a base class initialization. It says
It could happen directly or indirectly
What does this actually mean? How can the base class can somehow access to the overridden property in the derived class?
Also, it said
You should therefore avoid using open members in the constructors,
property initializers and init blocks.
So how can we properly use open properties?
EDIT FOR THE COMMENT:
fun main ()
{
val d = Derived("Test2")
}
open class Base()
{
open val something:String = "Test1"
init
{
println(something) //prints null
}
}
class Derived(override val something: String): Base()
What does this actually mean? How can the base class can somehow access to the overridden property in the derived class?
This is one direct way:
abstract class Base {
abstract val something: String
init {
println(something)
}
}
class Child(override val something: String): Base()
fun main() {
Child("Test") // prints null! because the property is not initialized yet
}
This prints null, which is pretty bad for a non-nullable String property.
You should therefore avoid using open members in the constructors, property initializers and init blocks.
So how can we properly use open properties?
You can use these properties in regular methods on the base class (or in custom property getters):
abstract class Base {
abstract val something: String
fun printSomething() {
println(something)
}
}
class Child(override val something: String): Base()
fun main() {
Child("Test").printSomething() // correctly prints "Test"
}
EDIT: Here are some clarifications regarding the follow-up questions in the comments.
I couldn't quite get why the code in the init block went for the parameter in the child class constructor
I think you might be confused by Kotlin's compact syntax for the primary constructors in general, which probably makes the debugger's flow hard to understand. In the Child declaration, we actually declare many things:
the argument something passed to the Child's primary constructor
the property something on the Child class, which overrides the parent's one
the call to the parent constructor (Base())
When Child() is called, it immediately calls the Base() no-arg constructor, which runs the init block.
We didn't even delegate the base constructor with a parameter or anything, but it still went for the parameter who did the overriding
You might be mixing declarations and runtime here. Although we declare things in the Base class and in the Child class, there is only 1 instance at runtime (an instance of Child) in this example code.
So, in fact, there is only 1 property called something here (only one place in memory). If the init block accesses this property, it can only be the property of the child instance. We don't need to pass anything to the Base constructor because the init block is effectively executed with the data/fields of the Child instance.
Maybe you would be less confused if you saw the Java equivalent of this. It's obvious if you think of the abstract something as a declaration of a getter getSomething(). The child class overrides this getSomething() method and declares a private something field, the getter returns the current value of the field something. But that field is only initialized after the constructor of the parent (and the init block) finished executing.
This SO post outlines how to test if a lateinit var has been initialized. However, in the example, the lateinit var is conveniently located within the same class.
How do you do the same thing from outside the class? This is the situation I have:
Foo.kt
class Foo {
lateinit var foo: String
}
Bar.kt
class Bar {
fun doSomething() {
val foo = Foo().foo
if (::foo.isInitialized) { // Unsupported [reference to variables aren't supported yet]
Log.i("TAG", "do something")
}
}
}
What's the workaround for this?
If this was going to work, you'd need to do
val foo = Foo()
if (foo::foo.isInitialized)
//...
The way you're doing it, you're trying to get a property reference of your local variable, which isn't a property. That's why the error says "reference to variables aren't supported yet" rather than "backing field not accessible at this point". Also, you'd be accessing the getter of the lateinit property when assigning the local variable, so it would fail if it weren't initialized yet.
But it doesn't work because of compiler limitations. You could simply add a getter
val fooReady: Boolean get() = ::foo.isInitialized
But I would say the design has very poor encapsulation if outside classes need to check whether a particular public property is initialized yet. In my opinion, any use of isInitialized is a code smell to begin with. If you need to guard calls to the getter with isInitialized, you might as well make the property nullable instead. Then you can use the familiar idioms of null checks instead of resorting to reflection, and it will work in a familiar way even for external classes that access it.
If object of another class has to make a decision based on whether or not the property is initialised, then having this property initialised - or answering whether or not it has already been initialised - is a public business capacity of your object and therefore I would recommend you to simply make it a part of your public API via public fun isFooInitialised(): Boolean function that utilises the fact that the object itself can inspect the state of its lateinit properties.
I have code (all of which I control) that looks like the following:
class FirstVeryLongName {
object ObjectA
object ObjectB
object ObjectC
}
class SecondVeryLongName {
object ObjectB
object ObjectD
}
The code I need to write is equivalent to
operation1(FirstVeryLongName.ObjectA, FirstVeryLongName.ObjectB)
operation2(SecondVeryLongName.ObjectB, SecondVeryLongName.ObjectD)
...except that the repeated uses of the very long names add a lot of clutter.
Here is something I hoped would work, but doesn't seem to:
FirstVeryLongName.run {
operation1(ObjectA, ObjectB)
}
...which I wasn't able to make work, even if I tried moving ObjectA and ObjectB into the companion of FirstVeryLongName and writing
FirstVeryLongName.Companion.run { ... }
...which I had hoped would give unqualified access to the objects, as it would have for a val in the companion object.
One thing I specifically want to avoid is typealiases or importing them as aliased names. I want it to be obvious without cross-references or manually looking at the imports where these are all coming from.
Is there some trick that would let me write this code and write FirstVeryLongName, ObjectA, and ObjectB each exactly once?
It makes sense to me that it isn't working the way you tried it.
The class name itself is no instance and run or with therefore doesn't apply. It's the same as just writing the package name and nothing else. This doesn't work either.
Regarding the Companion-approach, I assume you implemented the following:
class FirstVeryLongName {
companion object {
object ObjectA
object ObjectB
object ObjectC
}
}
and a usage such as:
with(FirstVeryLongName.Companion) {
operation1(ObjectA, ObjectB)
}
Actually this could work as long as you have such properties defined for the companion (this applies to functions as well). Actually that is also something you mentioned yourself. You may want to look at the generated byte code to see what an object actually corresponds to, if you didn't do it already. If you did, you can skip the rest of this paragraph ;-) Think of it as if it were just nested classes. In the example above we therefore have 3 nested classes inside the Companion-class, which is inside the FirstVeryLongName-class.
From Kotlin the access to the singleton INSTANCE-field is hidden from you. In the Kotlin code FirstVeryLongName.Companion.ObjectA can represent both, the type and the singleton instance reference. The context is relevant.
As you can't use class-names-only or part of an import-statement in run/with, you can't also simplify the access to the singleton instance in this way.
You can however do something as follows. Note: I clearly do not recommend this approach as is (I do not believe that you really need both: the object and the val). Maybe you can also use an object expression there? There is most probably an easier way to structure your code, but without appropriate context I can only guess... I may be wrong):
class FirstVeryLongName {
companion object {
val ObjectA = FirstVeryLongName.ObjectA // can you use an object expression here?
val ObjectB = FirstVeryLongName.ObjectA
val ObjectC = FirstVeryLongName.ObjectA
}
object ObjectA
object ObjectB
object ObjectC
}
Now the run/with works as you desire, but now it actually accesses the val-reference which points to the object:
with(FirstVeryLongName.Companion) {
operation1(ObjectA, ObjectB)
}
Just showing a simple example using an object expression. You may either want to have a common superclass, interface or, if you do not mind, you can even use object : Any() here:
class FirstVeryLongName {
companion object {
val ObjectA = object : interfaces.ObjectA { /* ... */ }
// ...
}
}
Usage still looks the same. Now only the signature of operation1 may differ.
I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.