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?
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.
using this reference expression as below:
val someOther = SomeOther().apply { someName = this#MyClass.someName }
// 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)
}
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 = this#SomeOther.someName }
fun go() = print(someOther.someName)
}
Try this:
val someName = "want this value"
val otherName = SomeOther().apply { this.someName = someName }
// internal someName ---^ ^
// external someName ---^
print(otherName.someName) // >>> want this name
Related
Consider following Kotlin-Code:
class Foo(input: Int) {
private var someField: Int = input
get() = -field
set(value) {
field = -value
}
fun bar() {
println(someField)
}
}
fun main() {
Foo(1).bar()
}
This prints -1 in the console which means that inside method bar() someField references the attribute and not the corresponding getter. Is there a way that allows me to use the get()-method as if I was referencing this field from outside?
Perhaps you could track the "raw" value separately from the negative value? Something like this:
class Foo(input: Int) {
private var _someField: Int = input
var someField: Int
get() = -_someField
set(value) {
_someField = -value
}
fun bar() {
println(someField)
}
}
Now the class internals can reference _someField to deal directly with the raw value, while outside clients can only "see" someField.
The following lambda expression operates on a class which was created outside of the lambda.
I consider this clumsy. Is there a better way to this?
class Builder {
var searchTerms = listOf<String>()
fun build(whatever: String): Builder {
searchTerms = searchTerms + whatever
return this
}
}
fun main() {
val b = Builder()
val toSearch = listOf<String>("Anna", "Berta", "Carla")
toSearch.forEach{ e-> b.build(e)}
}
Not exactly sure what you consider clumsy about it, but if it's that you have to create a distinct line for the temporary variable, you might consider this cleaner:
fun main() {
val toSearch = listOf<String>("Anna", "Berta", "Carla")
val b = toSearch.fold(Builder()) { builder, e -> builder.build(e) }
}
I had method that get data from database to list using Anko library. I can't figure out what mean single variable name after lambda (i.e dataList in the end of the function). How it's translate to Java?
Code:
fun gerData() : ArrayList<DataModelKotlin> = context.database.use {
val dataList = ArrayList<DataModelKotlin>()
select("TipList", "task", "id")
.parseList(object: MapRowParser<List<DataModelKotlin>>{
override fun parseRow(columns: Map<String, Any?>): List<DataModelKotlin> {
val task = columns.getValue("task")
val id = columns.getValue("id")
val dataModel = DataModelKotlin(text = task.toString(), id = id.toString().toInt())
dataList.add(dataModel)
return dataList
}
})
dataList //???
}
It is the same with
return dataList;
In Java
Last expression in lambda is its return value: https://kotlinlang.org/docs/reference/lambdas.html#returning-a-value-from-a-lambda-expression
I am new to kotlin. I wonder if this is possible
I wish to create a function that will change the value of the properties of the object and return the object itself. The main benefit is that I can chain this setter.
class Person {
var name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
try {
// the line below caused error
this[propName] = value
} catch(e:Exception){
println(e.printStackTrace())
}
}
}
}
//usage
var person = Person(null,null)
person
.setter(name, "Baby")
.setter(age, 20)
But I get error "unknown references"
This question is marked as duplicate, however the possible duplicate question specifically want to change the property of "name", but I wish to change anyProperty that is pass from the function to object. Can't seem to connect the dot between two questions. #Moira Kindly provide answer that explain it. thankyou
Why not just simplify your answer to
fun setter(propName: String, value: Any): Person {
val property = this::class.memberProperties.find { it.name == propName }
when (property) {
is KMutableProperty<*> ->
property.setter.call(this, value)
null ->
// no such property
else ->
// immutable property
}
}
Java reflection isn't needed, its only effect is to stop non-trivial properties from being supported.
Also, if you call it operator fun set instead of fun setter, the
this[propName] = value
syntax can be used to call it.
After googling around, I think I can provide an answer, but relying on java instead of kotlin purely. It will be great if someone can provide a better answer in kotlin.
class Person(
var name: String,
val age: Int
){
fun setter(propName: String, value: Any): Person{
var isFieldExistAndNotFinal = false
try{
val field = this.javaClass.getDeclaredField(propName)
val isFieldFinal = (field.getModifiers() and java.lang.reflect.Modifier.FINAL == java.lang.reflect.Modifier.FINAL)
if(!isFieldFinal) {
// not final
isFieldExistAndNotFinal = true
}
// final variable cannot be changed
else throw ( Exception("field '$propName' is constant, in ${this.toString()}"))
} catch (e: Exception) {
// object does not have property
println("$e in ${this.toString()}")
}
if(isFieldExistAndNotFinal){
val property = this::class.memberProperties.find { it.name == propName }
if (property is KMutableProperty<*>) {
property.setter.call(this, value)
}
}
return this;
}
}
usage like this
person
.setter(propName = "age", value = 30.00)
.setter(propName = "asdf", value = "asdf")
.setter(propName = "name", value = "A Vidy")
You have error because when you do this[propName] = value you are trying to use this as a list, but it is not a list, it is a Person and it doesn't overload the [] operator.
What you can do is to add a check for the property that is setted:
class Person {
privavar name:String? = null
var age:Int? = null
fun setter(propName:String, value:Any): Person{
return this.apply {
if (propName == "name" && value is String?) {
it.name = value as String?
} else if (propName == "age" && value is Int?) {
it.age = value as Int?
} else {
// handle unknown property or value has incorrect type
}
}
}
}
Another more dynamic solution without reflection:
class Person {
private var fields: Map<String, Any?> = HashMap()
fun setter(propName:String, value:Any): Person{
return this.apply {
it.fields[propName] = value;
}
}
fun getName() = fields["name"]
}
If you want to get rid of the getters as well then you need to use reflection.
Currently I have a private function which returns a Pair<User, User> object. The first user is the sender of something, the second user is the receiver of that thing.
I think this Pair<User, User> is not enough self explanatory - or clean if you like - even though it's just a private function.
Is it possible to return with an ad-hoc object like this:
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper): Any {
return object {
val sender = userCrud.findOne(instanceWrapper.fromWho)
val receiver = userCrud.findOne(instanceWrapper.toWho)
}
}
and use the returned value like this:
// ...
val users = findUsers(instanceWrapper)
users.sender // ...
users.receiver // ...
// ...
?
If not, what's the point of ad-hoc object in Kotlin?
Since the type can not be denoted in the language, use return type inference:
class Example {
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper) =
object {
val sender = userCrud.findOne(instanceWrapper.fromWho)
val receiver = userCrud.findOne(instanceWrapper.toWho)
}
fun foo() = findUsers(ExceptionInstanceWrapper()).sender
}
Another option would be to devise a data class:
class Example {
private data class Users(val sender: User, val receiver: User)
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper): Users {
return Users(
sender = userCrud.findOne(instanceWrapper.fromWho),
receiver = userCrud.findOne(instanceWrapper.toWho)
)
}
fun foo() = findUsers(ExceptionInstanceWrapper()).sender
}
Simply define your function as a lambda.
Here's simple object I've just written as an example in another context:
private val Map = {
val data = IntArray(400)
for (index in data.indices) {
data[index] = index * 3
}
object {
val get = { x: Int, y: Int ->
data[y * 20 + x]
}
}
}
fun main() {
val map = Map()
println(map.get(12,1))
}
Unfortunately, you cannot assign a type name, so it can be used as a return value but not as an argument. Maybe they'll make this possible so we can finally do OOP JS style.
Alternatively, they could implement object types equivalent to function types but that could end up being too wordy. You could then do a typedef but that would actually just be a kind of class definition 😅
Another option is to have a generic class for return types:
data class OutVal<T>(private var v: T?) {
fun set(newVal: T) {
v = newVal
}
fun get() = v
}
Usage example:
private fun findUsers(instanceWrapper: ExceptionInstanceWrapper,
sender: OutVal<String>, receiver: OutVal<String>) {
sender.set(userCrud.findOne(instanceWrapper.fromWho))
receiver.set(userCrud.findOne(instanceWrapper.toWho))
}
val sender = OutVal("")
val receiver = OutVal("")
findUsers(instanceWrapper, sender, receiver)
sender.get() // ...
receiver.get() // ...