The following code is posted on Kotlin's website:
class A { // implicit label #A
inner class B { // implicit label #B
fun Int.foo() { // implicit label #foo
val a = this#A // A's this
val b = this#B // B's this
val c = this // foo()'s receiver, an Int
val c1 = this#foo // foo()'s receiver, an Int
val funLit = lambda# fun String.() {
val d = this // funLit's receiver
}
val funLit2 = { s: String ->
// foo()'s receiver, since enclosing lambda expression
// doesn't have any receiver
val d1 = this
}
}
}
}
It isn't clear to me how you call a function in an inner class. For example, how do you call Int.foo()
var a = A()
a.Int.foo() // This is not allowed.
Lets look at a more simple example:
class A {
inner class B {
fun foo() {
// ...
}
}
}
To call a function within an inner class, you must access it using an instance of the outer class, like so:
A().B().foo()
What makes your example more difficult is that Int.foo() is an extension function, so to access it you must call foo() on an Int within the same scope as the extension function:
class A { // outer class A
inner class B { // inner class B
fun Int.foo() { // entension function foo
print("Foo called on integer $this")
}
fun caller(i: Int) { // calls extension function
i.foo()
}
}
}
fun main() {
A().B().caller(10) // calls extension function in inner class B
}
Here we have added a function caller which is in the same scope as the extension function. The code outputs the following:
Foo called on integer 10
In this case, foo is an extension function defined in B. You cannot call these member extension functions from outside by default. However, it's possible to execute the function when you get into the scope of B, which can be achieved with scoping functions such as with. Please be aware that this extension function can only be called on instances of Int.
val a = A()
val b = a.B()
with(b) {
5.foo()
}
Related
data class Outer(val x: Int = 1, val predicate: Predicate<Int> = Inner()) {
private inner class Inner : Predicate<Int> {
override fun test(t: Int): Boolean = x == t
}
}
I get an error Constructor of inner class Inner can be called only with receiver of containing class where Inner() is called. Also if I do this.Inner() I get 'this' is not defined in this context.
I realise I can do:
data class Outer(val x:Int, val predicate: Predicate<Int> = Predicate<Int> { it == x }) {
}
but I want my Inner to be Seralizable so it cannot be an anonymous class.
inner classes are like non-static inner classes in Java, and you need an instance of Outer to create them. However, when specifying the default values of the constructor parameters, the instance of Outer that you are creating (aka this) has not been created yet, so you cannot do this.Inner().
For this scenario, you can remove inner, to make the Inner class more like a static inner class in Java. Add an Int constructor parameter to it so that you can pass the x from the outer to it:
data class Outer(val x: Int = 1, val predicate: Predicate<Int> = Inner(x)) {
private class Inner(val x: Int) : Predicate<Int> {
override fun test(t: Int): Boolean = x == t
}
}
I just came across a data class as follows.
class A{
}
sealed class B
data class C(val isNext: Boolean = false, val builder: () -> A): A
class D: A{
}
To create an instance of the class, the developer used the following declaration.
C{D()}
My understanding of lambda, () -> A is that its a function without name that takes no arguments and creates an instance of A, however given that A's constructor is called, can I presume that its a function?
A constructor is a type of function, but you aren't passing it as a function here, because you have wrapped it by calling it in a lambda function. So you have passed a function that internally calls the constructor.
You can pass the constructor directly as a function, like this:
val c = C(::D)
I tidied up your setup:
open class A
class C(val isNext: Boolean = false, val builder: () -> A) : A()
class D : A()
With that in place the following are all equivalent:
val bldr: () -> A = { D() }
C { D() }
// is the same as:
C(isNext = false, builder = { D() })
// is the same as:
C(isNext = false, builder = bldr)
So the lambda is just an instance variable named builder of C just like isNext is. If it gets invoked in will create a new D that happens to be a subclass of A
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.
I am new to Kotlin. I came across the Object Expressions section of https://kotlinlang.org
Some of the object expression syntaxes are very straight forward to understand,
Create an object of an anonymous class
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
})
Just an object
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
But I am unable to understand the "Object expression with multiple supertypes specified" example given as below:
open class A(x: Int) {
public open val y: Int = x
}
interface B { ... }
val ab: A = object : A(1), B {
override val y = 15
}
What's happening here?
${ab.y} prints 15
but syntax -> ${ab.A.y} is not valid. My understanding of ${ab.A.y} it will print 1 :)
This line here:
val ab: A = object : A(1), B {
means that the class of ab is inherited from class A and implements interface B.
Actually the code example you gave will only compile if you declare and implement the interface. This is a possible implementation:
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun hi()
}
val ab: A = object : A(1), B {
override val y = 15
override fun hi() {
println("hi")
}
}
The expression ${ab.A.y} does not make much sense in this context, because the object ab does not have any field A. A is just the inherited superclass to which you could eventually cast.
It basically creates object ab with class type A with implementation of interface B.
So, let's say your class A has some method foo() & interface B has some method bar(), you can access them both on object ab as it's of class type A with implementation of B.
Hence, here you override variable y with value 15 meaning your superclass variable y will get overridden by value 15 from 1.
My question is almost like this question Java: calling outer class method in anonymous inner class .
But this time we are in Kotlin.
As the example below, I want to call funB() in the object expression, but I only made two failures.
class A {
lateinit var funA: () -> Unit
lateinit var funB: () -> Unit
fun funC() {
var b = object : B() {
override fun funB() {
funA() // A.funA()
// Two attempts to fail
funB() // b.funB(), not my expect
A::funB() // compile error
}
}
}
}
Thank you for your answer!
You can qualify this with a # to obtain an equivalent of java: MyClass.this
->this#MyClass
Then in your case, you can call:
this#A.funB()
From the doc:
To access this from an outer scope (a class, or extension function, or labeled function literal with receiver) we write this#label where #label is a label on the scope this is meant to be from:
class A { // implicit label #A
inner class B { // implicit label #B
fun Int.foo() { // implicit label #foo
val a = this#A // A's this
val b = this#B // B's this
val c = this // foo()'s receiver, an Int
val c1 = this#foo // foo()'s receiver, an Int
val funLit = lambda# fun String.() {
val d = this // funLit's receiver
}
val funLit2 = { s: String ->
// foo()'s receiver, since enclosing lambda expression
// doesn't have any receiver
val d1 = this
}
}
}
}