Is it possible to bind a class member in kodein? - kotlin

There is 2 classes:
A - base class
B - class of member of A
with implementation something like this:
class A {
val b : B = B()
}
class B
Problem
Is it possible to create a binding for b to hide redundant info about b source in common classes?
Kodein declaration:
override val kodein by Kodein.lazy {
bind<A>() with singleton { A() }
bind<B>() with "a.b some impl???"
}
Usecase
class Usecase(kodein : Kodein){
val b : B = kodein.instance()
}

Very simple :
bind<B>() with provider { instance<A>().b }
The provider binding is the simplest one : it will call the provided function everytime.
The function itself runs inside a Kodein context, hence the use of the instance function.

Related

Accessing the outer class when inheriting from it

abstract class A {
abstract inner class B : A() {
init {
// How can I access the outer class?
}
}
}
In this example, this refers to the class B, this#A refers to the parent class. How can I access the outer class?
Test case:
abstract class A {
abstract inner class B : A() {
init {
println("Should display 'Parent': $this") // replace 'this' by something else?
}
}
}
class Parent : A() {
override fun toString() = "Parent"
inner class Child() : B() {
override fun toString() = "Child"
}
}
fun main() {
Parent().Child()
}
In your example, you created two objects - an instance of Parent, and an instance of Child.
Parent().Child()
^ ^
| |
1 2
So there is really only two different things that you can access from the init block of B. You can either access the Parent object using this#A, which is the object associated with the Child object, or the Child object itself using this (or redundantly this#B).
"Accessing the outer class", which presumably you mean A, is not something you can do, because there is not even such an instance of A.
You can however, invoke A's implementations of methods/properties using super#B.xxx (note that it is not super#A. Read it as "super of B"). Perhaps this is what you intended on doing in the first place.
For example, changing A to the following:
abstract class A {
override fun toString() = "A"
abstract inner class B : A() {
init {
println("Should display 'Parent': ${super#B.toString()}")
}
}
}
would print "A".
Note that this actually calls toString on the Child object, not the Parent object. You cannot do the same to the Parent object, because it is a different object. This init is creating the Child object, right?
In summary, this accesses some object that is in scope. super accesses a specific implementation of a method/property up the inheritance hierarchy.

Kotlin inner class can't resolve extension function declared in outer class

Why inner class in Kotlin can't not access extension function declared in outer class as below:
class A{
val a = "as".foo() // LINE 1
class B{
val b = "as".foo() // LINE 2
}
fun String.foo(){}
}
On LINE 1 extension function is resolved but on LINE 2 the function is not resolved. Wonder why there is such limitation?
This is not an inner class, because you didn't use the keyword inner on it. It is merely a nested class. If you're familiar with Java, it's like a static inner class. Since it is not inner, it does not have any implicit reference to the outer class, and cannot make bare calls to members of the outer class since there is no specific instance to use the members of. It can however call members of the outer class on an instance of the outer class, so you could for example do the following:
class A{
val a = "as".foo()
class B{
val b = A().run { "as".foo() }
}
fun String.foo(){}
}
Even though foo is an extension function, it's also a member of A because of where it's declared. Using a scope function that causes a class to be a receiver inside the scope is one way to call one of its member extension functions from another class.
EDIT: Here's an example of one reason you'd want to declare an extension inside a class.
class Sample(val id: Int) {
private val tag = "Sample#$id"
fun String.alsoLogged(): String{
Log.d(tag, this)
return this
}
}
You can use this extension to easily log Strings you're working with inside the class (or when it's the receiver of run or apply). It wouldn't make sense to declare outside the class because it uses the private tag property of that class.
It's because Kotlin compiles your code to
public final class A {
#NotNull
private final Unit a;
#NotNull
public final Unit getA() {
return this.a;
}
public final void foo(#NotNull String $this$foo) {
Intrinsics.checkNotNullParameter($this$foo, "$this$foo");
}
public A() {
this.foo("as");
this.a = Unit.INSTANCE;
}
public static final class B {
public B() {
// You can't access A's foo() method here.
}
}
}

Access a Kotlin Outer class using the inner object from somewhere else

I have the following setup:
class A {
fun runA() {
}
inner class B {
fun runB() { // Proxy method for runA()
runA() // its okay to call it here
}
}
}
fun test() {
val obj = A().B()
obj.runA() // how to call this one??
obj.runB() // i do not want to add a proxy method for everything in A
}
Is there any way to call runA() when I only have the B object?
Every instance of B is always coupled to an instance of A, so it should theoretically be possible (and as I am able to call runA() from within B proves that)
Best solution that I currently have is providing a accessor of A within B like so:
inner class B {
fun a(): A = this#A
fun runB() {
runA()
}
}
and then call it like obj.a().runA()
Would be nice if I could just directly call obj.runA(), I don't see a reason why it shouldn't be technically possible other than the compiler not allowing it.
Thanks for your input!
B is not A. The compiler gives B a private reference to his own A, because he needs it to execute runA. But it is private, doesn't mean that you can access from there. You can just write runA and it works inside runB because an inner class has all the members of the parent class in scope, kind of like when you use a closure. See the analogy with this example:
class A {
fun runA() {
}
fun B {
{
runA() // its okay to call it here
}
}
}
fun test() {
val obj = A().B()
obj()
}
Similarly to what you saw with the inner class, inside the closure object created when you call the member B() you can access to all variables in scope (including the instance of A that was used to invoke B()).
If you want an object B that has all the members of A you should probably have a look at inheritance instead of inner classes. Or expose an accessor to A instance like you did.

Get a reference to the class of the calling function

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.

How can I create a Factory that produces objects based on a type or a Class object?

In my Kotlin application I have a few entities (and a data class for each of them) and for each entity I have a service object implementing generic Service<T> interface.
I want to create a Factory of services that will return me a proper service based on a parameter which is a type of entity I want to have a service for. In Java I would pass a Class object into the factory which I could obtain from a static context of the entity class eg. Entity.class but I can't do that in Kotlin. How can I create a Factory that will produce me objects based on a type of an entity?
You're looking for KClass:
Say you have the following classes:
abstract class Parent(val name: String)
class ChildA : Parent("A")
class ChildB : Parent("B")
Then your factory may look like this:
fun <T : Any> factory(c: KClass<T>): T {
return c.createInstance()
}
fun main(args: Array<String>) {
val childA = factory(ChildA::class)
val childB = factory(ChildB::class)
println(childA.name) // A
println(childB.name) // B
}
But there's a better way using reified:
inline fun <reified T : Any> factory(): T {
return T::class.createInstance()
}
Then you can call it like this:
val childA = factory<ChildA>()
val childB = factory<ChildB>()
println(childA.name)
println(childB.name)
Note that without using reified we couldn't do T::class