I was thinking about such case (accessing outer class which uses current class to implement some stuff):
interface Does {
fun doStuff()
}
class ReallyDoes: Does {
var whoShouldReallyDo: Does? = null
override fun doStuff() {
println("Doing stuff instead of $whoShouldReallyDo")
}
}
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other.also { it.whoShouldReallyDo = this }, 42)
}
fun main(args: Array<String>) {
val worker = ReallyDoes()
val boss = MakesOtherDo(other = worker)
boss.doStuff()
}
Expected output:
Doing stuff instead of MakesOtherDo#28a418fc
But can't do that, because of error:
Error:(15, 79) Cannot access '' before superclass constructor
has been called
Which targets this statement: other.also { it.whoShouldReallyDo = this }
How can I (if at all) fix above implementation?
The reason for the error is other.also { ... = this } expression accesses this of type MakeOtherDo and is also used as argument to MakeOtherDo constructor. Hence, this will be accessed as part of MakeOtherDo (unary) constructor before this has been initialized as an instance of Does (super)class.
Since the assignment does not affect the initialization of the super class, you can executed it in the constructor of MakesOtherDo after the super class has been initialized.
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other, 42) {
other.also { it.whoShouldReallyDo = this }
}
}
It took me a few minutes to decipher what you were doing above, and really the problem has nothing to do with delegates. You can simplify it down to this:
class Wrapper(var any: Any? = null)
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper(this)) // Cannot access "<this>" before superclass constructor has been called
}
The concept of "this" doesn't exist yet when we're still generating arguments for its constructor. You just need to move the assignment into the block of the constructor, which is code that's run after this becomes available:
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper()){
wrapper.any = this
}
}
Or in the case of your example:
constructor(other: ReallyDoes): this(other, 42){
other.whoShouldReallyDo = this
}
Related
Is it impossible to use generic on interface level as argument type for function?
I read about out and in keywords but as I understand they don't work for this case.
interface BaseB
open class ChildB1: BaseB
open class ChildB2: BaseB
abstract class BaseMapper<V: BaseB> {
open fun test(v: V) {
return
}
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
return
}
}
class TestMapper2: BaseMapper<ChildB2>() {
override fun test(v: ChildB2) {
return
}
}
#Test
fun t() {
//ERROR
val mappers: List<BaseMapper<BaseB>> = listOf(TestMapper1(), TestMapper2())
mappers[0].test(ChildB1())
}
A BaseMapper<ChildB1> is not logically a BaseMapper<BaseB>. It consumes ChildB’s, so if you passed some other implementation of Base it would cause a ClassCastException if the compiler let you do that. There is no common subtype of your two subclasses besides Nothing, so the only way to put both of these types in the same list is to make it a List<BaseMapper<in Nothing>>.
Example of why it is not logically a BaseMapper<BaseB>:
open class ChildB1: BaseB {
fun sayHello() = println("Hello world")
}
class TestMapper1: BaseMapper<ChildB1>() {
override fun test(v: ChildB1) {
v.sayHello() // if v is not a ChildB1, this would be impossible
}
}
//...
val impossibleCast: BaseMapper<BaseB> = TestMapper1()
// TestMapper1 cannot call sayHello() because it's undefined for ChildB2.
// This is impossible:
impossibleCast.test(ChildB2())
// ...so the compiler prevents you from doing the impossible cast in the first place.
Why does kotlin report Property must be initialized or be abstract. The object construction is never finished, so it should not matter whether a is initialized or not. Could a case be demonstrated where this would be a problem?
class Foo {
private val a: Int
init {
a = 42
throw Exception()
}
}
fun main() {
Foo()
}
kotlin playground
However these work just fine
fun bar() {
throw Exception()
}
class Foo {
private val a: Int
init {
a = 42
bar()
}
}
fun main() {
Foo()
}
kotlin playground
class Foo {
private val a: Int = throw Exception()
}
fun main() {
Foo()
}
kotlin playground
Similar java code works as expected:
public class Test {
private static class Foo {
private final int a;
public Foo() throws Exception {
a = 42;
throw new Exception();
}
}
public static void main(String []args) throws Exception {
new Foo();
}
}
The question is very well answered in the below link.
Kotlin: why do I need to initialize a var with custom getter?
Essentially it boils down to having a backing field for every "val" (property) . If you can provide a backing field, you need not initialize the field. Below is a small example of it.
class Foo {
private val a: Int
get() = getValue()
}
fun getValue():Int {
throw Exception()
}
fun main() {
Foo()
}
Similar java code works as expected:
Java initializes fields to 0 (or null/false depending on type) by default. You can see it e.g. by printing a's value before the a = 42 line.
Kotlin doesn't, because this implicit initialization makes it too easy to forget to initialize a property and doesn't provide much benefit. So it requires you to initialize all properties which have backing fields.
It seems to be a compiler bug as Alexey suggested
There is similar issue posted on Kotlin bug tracer.
I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}
Is there a way to get the javaClass of the companion class inside a companion object without knowing it's name?
I suppose I could get it by doing something like this:
open class TestClass {
companion object {
init {
val clazz = Class.forName(this::class.java.canonicalName.removeSuffix(".Companion"))
}
}
}
However, this does not work for class InheritingClass : TestClass(). It would still give me TestClass, not InheritingClass.
I was hoping for something more straightforward like this::class.companionClass.
Getting the class of the companion object of a given class will look like this:
TestClass::class.companionObject
Here's an example:
class TestClass {
companion object {
fun sayHello() = "Hello world"
}
}
If you want to get the class that contains the companion, since the latter is always an inner class of the former,
class TestClass {
companion object {
fun whichIsMyParentClass() = this::class.java.declaringClass // It'll return TestClass
}
}
And to further simplify, you'll also want to create an extension property:
import kotlin.reflect.KClass
val <T : Any> KClass<T>.companionClass get() =
if (isCompanion)
this.java.declaringClass
else
null
So, whenever you want to get the parent class of the companion object,
class TestClass {
companion object {
fun whichIsMyParentClass() = this::class.companionClass // It'll return TestClass
}
}
The companion class itself has no reference to the actual class as you can see in this bytecode
public final class TestClass$Companion {
private TestClass$Companion() { // <init> //()V
<localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>
L1 {
aload0 // reference to self
invokespecial java/lang/Object <init>(()V);
return
}
L2 {
}
}
public TestClass$Companion(kotlin.jvm.internal.DefaultConstructorMarker arg0) { // <init> //(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
<localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>
<localVar:index=1 , name=$constructor_marker , desc=Lkotlin/jvm/internal/DefaultConstructorMarker;, sig=null, start=L1, end=L2>
L1 {
aload0 // reference to self
invokespecial TestClass$Companion <init>(()V);
return
}
L2 {
}
}
}
The reference is only the other way around (see decompiled kotlin class)
public final class TestClass {
public static final Companion companion = ...
}
So you can either do it as you just did by cutting off the .Companion part of the class name or you reference it by hard with TestClass::class.java (what is in my opinion no problem and the best solution)
If you need to print the class name, you can add simpleName, such as
this::class.java.declaringClass.simpleName
With this example:
open class Parent {
fun some():Parent {
return this;
}
}
class A : Parent(){
val name:String? = null;
}
But then this code results in an error:
val a = A().some().some()
a.name // ERROR
EDITOR NOTE: based on comments of the author to answers below, the question is NOT about referencing a.name but really is about something like "how do I get the instance of the class or its name that first started the chain of method calls". Read all comments below until the OP edits this for clarity.
my final goal is to return caller's type and can call this caller's instance property, no more as , no more override, any idea?
Just like java, you can use stackTrace's getMethodName(). Refer to the kotlin doc.
Actially your example is working(if you add open keyword because all classes in Kotlin are final by default:
A.kt
open class A {
fun some(): A {
return this
}
}
B.kt
class B : A() {
val test = "test"
}
And usage
val tmpB = (B().some().some() as B)
val test = tmpB.test
Edited:
It because function some() return parent class which doesn't have child class property. So you need to cast it to child class.(Update code)
open class Parent{
open fun foo(): Parent {
return this;
}
}
This is your Parent class. Parent class has a method named foo(). foo() is a method of class A which will return the instance of it's own class. We must have to open the class and method because by default their visibility modifier is final.
class A : Parent() {
override fun foo(): A { return this }
}
This is a class named A which extends Parent class. foo() is a method of class A which will return the instance of it's own class.
We will call it like this:
var a = A().foo().foo()
Your class always return Parent instance. This class do not have any field with the name name. To do that you have 2 ways:
The first:
open class Parent{
fun some():Parent{
return this
}
}
class A :Parent(){
val name:String? = null
}
fun main() {
val a = (A().some().some() as A)
a.name = "";
}
The second:
open class Parent{
open fun some():Parent{
return this
}
}
class A :Parent(){
override fun some():A {
return this
}
val name:String? = null
}
fun main() {
val a = A().some().some()
a.name = "";
}
i have know how to do this:
#Avijit Karmakar
#Trần Đức Tâm
use inline function
inline fun <reified T:Any> some(sql: String):T {
return this as T ;
}