When I have two classes (A and B) and A has a function called myFunA which then calls myFunB (inside of class B), is it possible for code in myFunB to obtain a reference to the class A that is used to call myFunB? I can always pass the reference as a parameter but I am wondering if Kotlin has a way of allowing a function to determine the instance of the parent caller.
class A {
fun myFunA() {
val b = B()
b.myFunB() {
}
}
}
class B {
fun myFunB() {
// Is it possible to obtain a reference to the instance of class A that is calling
// this function?
}
}
You can do it like this:
interface BCaller {
fun B.myFunB() = myFunB(this#BCaller)
}
class A : BCaller {
fun myFunA() {
val b = B()
b.myFunB()
}
}
class B {
fun myFunB(bCaller: BCaller) {
// you can use `bCaller` here
}
}
If you need a reflection-based approach, read this.
Related
I have an interface:
interface EmployeeActions
interface SalesEmployeeActions : EmployeeActions {
fun onSaleRequest()
//..more functions
}
interface HREmployeeActions : EmployeeActions {
}
...//more EmployeeActions
Now the way I am using this in the class is basically an aggregation where I will have many of these objects and I want to call stuff on them all together.
class FakeEmployeeDb {
val employees: MutableList<EmployeeActions> = mutableListOf()
private val salesEmployees:
get() = employees.filterIsInstance<SalesEmployeeActions>()
....
val salesManager = object: SalesEmployeeAction {
fun onSaleRequest() {
salesEmployees.forEach { it.onSaleRequest() }
}
... //more functions
}
private val .... // other Managers
// also at some point employees are added using this API...
fun addEmployee(employee: EmployeeActions) {
employees.add(employee)
}
}
Question:
Is there a kotlin-y way of writing this code in a scalable way?
In the real case, the client will only call APIs on these xyzManager objects and the job of each of them is to simply pass that information down to all employees.
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
}
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)
}
...
}
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 ;
}
in C sharp, if we have 2 interfaces, with the same signature method, we can implement them in one class, in the following way:
interface A
{
void doStuff();
}
interface B
{
void doStuff();
}
class Test : A, B
{
void A.doStuff()
{
Console.WriteLine("A");
}
void B.doStuff()
{
Console.WriteLine("A");
}
}
If we thranslate this to Kotlin we have
interface A
{
fun doStuff()
}
interface B
{
fun doStuff()
}
class Test : A, B
{
override fun doStuff() {
println("Same for A b")
}
}
fun main(args: Array<String>)
{
var test = Test();
test.doStuff() //will print Same for A b"
var InterfaceA:A = test
var InterfaceB:B = test
InterfaceA.doStuff()//will print Same for A b"
InterfaceB.doStuff()//will print Same for A b"
}
So, my question is, how can I
give to each interface a different implementation as in C sharp example?.
**Note: I have read the docs on https://kotlinlang.org/docs/reference/interfaces.html , there is a similar example,
interface A {
fun foo() { print("A") }
}
interface B {
fun foo() { print("B") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
}
Here, foo is implemented in each interface, so when implemented in D, it just call the implementation defined in the interface. But how can we give define different implementation in D?.
It is not possible in Kotlin. Kotlin is similar to Java in this respect. Methods that are override-equivalent in interfaces must have the same implementation in a class. The rationale behind that behavior is that casting a object reference to different types should not change behavior of its methods, e.g:
val test = Test()
(test as A).doStuff()
(test as B).doStuff() // should do the same as above