Home > Software design >  Can a method parameter contain a reference to other variable instead of containing a value?
Can a method parameter contain a reference to other variable instead of containing a value?

Time:12-19

In the code below, i'd like to generalize it so I instead of viewBinding.editText.text and viewModel.property.price can use the same method for e.g viewBinding.secondEditText.text and viewModel.property.income.

I'm thinking exchanging viewBinding.editText.text for a variable defined in the primary constructor, but then I'd need the variable to contain a reference to viewBinding.editText.text/viewBinding.secondEditText.text etc. instead of containing a value.

Is this possible? I've looked at lengths for this but can't find anything useful.

    fun updateProperty() {

        //... other irrelevant code

        if (viewBinding.editText.text.toString() != "") {
            viewModel.property.price = viewBinding.editText.text.toString().toDouble() 
        }

        //... other irrelevant code

    }

CodePudding user response:

You can pass parameters into a function, yeah!

This is the easy one:

fun updateProperty(editText: EditText) {
    val contents = editText.text.toString()
}

simple enough, you just pass in whatever instance of an EditText and the function does something with it.

If you're just using objects with setters and getters, you can just define the type you're going to be using and pass them in. Depending on what viewmodel.property is, you might be able to pass that in as well, and access price and income on it. Maybe use an interface or a sealed class if there are other types you want to use - they need some commonality if you're going to be using a generalised function that works with them all.


Properties are a bit tricker - assuming viewmodel.property contains a var price: Double, and you didn't want to pass in property itself, just a Double that exists somewhere, you can do it like this:

import kotlin.reflect.KMutableProperty0

var wow: Double = 1.2

fun main() {
    println(wow)
    setVar(::wow, 6.9)
    println(wow)
}

fun setVar(variable: KMutableProperty0<Double>, value: Double) {
    variable.set(value)
}

>> 1.2
>> 6.9

(see Property references if you're not familiar with the :: syntax)

KMutableProperty0 represents a reference to a mutable property (a var) which doesn't have any receivers - just a basic var. And don't worry about the reflect import, this is basic reflection stuff like function references, it's part of the base Kotlin install

CodePudding user response:

Yes, method parameters can also be references to classes or interfaces. And method parameters can also be references to other methods/functions/lambdas.

If you are dealing with cases that are hard to generalize, consider using some kind of inversion of control (function as parameter or lambda).

You add a lambda parameter to your updateProperty function

    fun updateProperty(onUpdate: (viewBinding: YourViewBindingType, viewModel: YourViewModelType) -> Unit) {

        //... other irrelevant code

        // here you just call the lambda, with any parameters that might be useful 'on the other side'
        onUpdate(viewBinding, viewModel)

        //... other irrelevant code

    }

Elsewhere in code - case 1:

updateProperty() { viewBinding, viewModel ->
    if (viewBinding.editText.text.toString() != "") {
        viewModel.property.price = viewBinding.editText.text.toString().toDouble() 
    }
}

Elsewhere in code - case 2:

updateProperty() { viewBinding, viewModel ->
    if (viewBinding.secondEditText.text.toString() != "") {
        viewModel.property.income = viewBinding.secondEditText.text.toString().toDouble()
    }
}

Elsewhere in code - case 3:

updateProperty() { viewBinding, viewModel ->
    // I am a totally different case, because I have to update two properties at once!
    viewModel.property.somethingElse1 = viewBinding.thirdEditText.text.toString().toBoolean()
    
    viewModel.property.somethingElse2 = viewBinding.fourthEditText.text
        .toString().replaceAll("[- ]*", "").toInt()
}

You could then go even further and define a function for the first 2 cases, since those 2 can be generalized, and then call it inside the lambda (or even pass it as the lambda), which would save you some amount of code, if you call updateProperty() in many places in your code or simply define a simple function for each of them, and call that instead, like this

fun updatePrice() = updateProperty() { viewBinding, viewModel ->
    if (viewBinding.editText.text.toString() != "") {
        viewModel.property.price = viewBinding.editText.text.toString().toDouble() 
    }
}

fun updateIncome() = updateProperty() { viewBinding, viewModel ->
    if (viewBinding.secondEditText.text.toString() != "") {
        viewModel.property.income = viewBinding.secondEditText.text.toString().toDouble()
    }
}

Then elsewhere in code you just call it in a really simple way

updatePrice()

updateIncome()
  • Related