Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to external value inside apply

Tags:

kotlin

Short example:

class MyClass {
 val someName = "want this value"
 val someOther = SomeOther().apply{ someName = someName }
 // other stuff below
}

SomeOther will apply the value of its own someName to someName, so value application makes no difference (x=x).

Q: How can I access external someName ("want this value") being inside apply?

UPDATE I have further doubts related to suggestion to use this.someName=someName, below 2 code snippets, the first one works as expected, surprisingly the second fails with similar behavior as described.

First

fun main(args: Array<String>) {
    class SomeOther {
        var someName: String? = null
    }
    val someName = "want this value"
    print(SomeOther().apply { this.someName = someName }.someName) // works!

}

Second

class SomeOther {
    var someName: String? = null
}

class MyClass {
    val someName = "want this value"
    val someOther = SomeOther().apply { this.someName = someName }
    fun go() = print(someOther.someName)
}

fun main(args: Array<String>) = MyClass().go() // prints null

Q: Where's the difference?

like image 994
wilu Avatar asked Jul 06 '17 11:07

wilu


4 Answers

You could use the also-function instead. It is equivalent to apply, except it will bind your object to it instead of this:

val someName = "want this value"
val someOther = SomeOther().also { it.someName = someName }

The also-function was added to Kotlin 1.1 specifially for when you do not want to shadow this from the outer scope.

like image 122
marstran Avatar answered Nov 09 '22 22:11

marstran


using this reference expression as below:

val someOther = SomeOther().apply { someName = [email protected] }
//                 reference to the outer class ---^

AND the T.apply function is a convenient way to applying Builder Design Pattern, in this way you never need using this or additional parameter at all, for example:

val foo = Foo().apply {
  //v--- no need using `this` or any addition parameters
    foo = "bar"
    fuzz = "buzz"
}

class Foo {
    lateinit var foo: String;
    lateinit var fuzz: String
}

Edit

you can assuming apply(lambda) which will apply an anonymous class of Function2<T,ARG,T> instance, then you know why immediately?

in your first approach it looks like as below:

val lambda: Function2<SomeOther, String, SomeOther> = { thisRef, arg ->
    thisRef.someName = arg;
    //                 ^--- parameter is used in lambda
    thisRef
}

val someName = lambda(SomeOther(), "want this value").someName

println(someName)

in your second approach it looks like as below:

class MyClass {
    val lambda: Function2<SomeOther, MyClass, SomeOther> = { thisRef, arg ->
        //              the parameter `arg` is never used in lambda ---^
        thisRef.someName = thisRef.someName
        //                    ^--- it use thisRef's someName rather than arg's
        thisRef
    }

    val someOther = lambda(SomeOther(), this)
}
like image 24
holi-java Avatar answered Nov 09 '22 22:11

holi-java


You can access out of apply like that

class SomeOther {
    var someName: String? = null
}

class MyClass {
    val someName = "want this value"
    val someOther = SomeOther().apply { this.someName = [email protected] }
    fun go() = print(someOther.someName)
}
like image 3
nebyan Avatar answered Nov 09 '22 22:11

nebyan


Try this:

val someName = "want this value"
val otherName = SomeOther().apply { this.someName = someName }
//                     internal someName ---^          ^
//                                external someName ---^

print(otherName.someName) // >>> want this name
like image 1
Alexander Romanov Avatar answered Nov 09 '22 22:11

Alexander Romanov