I am learning Kotlin and I came across Functional Interfaces here:
https://kotlinlang.org/docs/fun-interfaces.html#sam-conversions, and I don't quite understand the purpose of declaring and using an interface like in the example. The example is as follows:
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
// Creating an instance of a class
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
// Or creating an instance using lambda
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
Now why do this when we can declare a function isEven and then call it whenever we want, like this:
fun isEven(i: Int): Boolean {
return i % 2 == 0
}
fun main() {
println("Is 7 even? - ${isEven(7)}")
}
And we get the same result. I think I am missing something here, can anybody help with an explanation.
Now I get what lambda expression is but what does exactly these lines of code do (I have seen before in other files but didn't understand it)
// Creating an instance of a class
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
Thanks!
Your question isn't really about Kotlin and functional interfaces, but about fundamental concepts of object oriented programming. The question you ask is: why do we need interfaces if we can just use normal classes/functions? It is to abstract software components; to decouple caller of the function and its implementation.
Imagine we have a function that is used to filter a list of integers. It doesn't know rules for filtering, it receives them from external code in the form of IntPredicate. It could be declared as:
fun filterList(list: List<Int>, predicate: IntPredicate): List<Int> = TODO()
interface IntPredicate {
fun accept(i: Int): Boolean
}
Because we have to provide an implementation of IntPredicate, using this function is quite cumbersome. For each use we need another implementation of IntPredicate. Even if we need to perform a very simple filtering, like looking for odd numbers. This seems like a much of work for such a simple case.
Functional interfaces and SAM conversions makes such cases much easier to use. After declaring predicate interface as fun interface IntPredicate, we can use our function like this:
filterList(list) { it % 2 == 0 }
Now, we can provide lambda instead of implementing a whole class.
Functional interfaces are not something entirely new, they won't let you do anything that would be not possible without them. By marking interface as fun we just enable a useful syntactic sugar for this interface.
Note that in practice my example does not make too much sense. We already have a very similar filter() function in stdlib, and in Kotlin we usually prefer function types over interfaces in such cases.
Related
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
}
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
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()
I've been considering a few solutions for reducing boilerplate in a large number of fragments that have the same patterns and workflows.
The best solution I've come up with is to abstract a lot of the standard tasks into an abstract class and then force the implementing fragments to override methods that determine the unique flavor for their particular context.
For the sake of providing an example, here's something I'm making up to illustrate the problem.
abstract class ContainsRepetiveBoilerPlate<T:View,U:InfoForView>:Fragment(){
fun performNinetyPercentOfTheWork(){//tedious stuff that's always the same}
val thingThatChildMightWantToAccess=mutableListOf<U>()
fun upDateUsefullThing(){//update thingThatChildMightWantToAccess}
abstract fun fullFillContractToBindViewToItsInformation(t:T,u:U)
}
Now the fragment will look like this:
class HasATTypeViewPopulatedFromAUTypeDataClass:ContainsRepetitiveBoilerplate<T,U>(){
override fun fullfillContractToBindViewToItsInformation(t:T,u:U){//for every view inside of T, give it values from u}
Setting aside just for one moment the why, of which there are many. I'm interested to know any hows for forcing the child to somehow acknowledge that it's aware of thingThatChildMightWantToAccess.
Likewise, what tools are available to force the child to call performNinetyPercentOfTheWork()?
I've seen a couple of good ideas surrounding making performNinetyPercentOfTheWork() include a call to an abstract fun. But it would be awesome if I could make the linter complain if the child never calls it.
Here's a really really stupid solution that isn't at all serious but would help you understand what I want to achieve.
abstract class ContainsRepetiveBoilerPlate<T:View,U:InfoForView>:Fragment(){
var hasBeenCalled=false
fun performNinetyPercentOfTheWork(){hasbeenCalled=true //do other stuff}
val thingThatChildMightWantToAccess=mutableListOf<U>()
fun upDateUsefullThing(){//update thingThatChildMightWantToAccess}
abstract fun fullFillContractToBindViewToItsInformation(t:T,u:U)
override fun onViewCreated(){
toBeInvokedDuringOnViewCreated()
if (!hasBeenCalled){throw Error("you need to call performNinetyPercentOfTheWork()"}
abstract fun toBeInvokedDuringOnViewCreated()
}
Ok, here's an even stupider example, solely for the sake of trying to illustrate the functionality that I want from the linter.
abstract class ContainsRepetiveBoilerPlate<T:View,U:InfoForView>:Fragment(){
var hasBeenCalled=false
fun performNinetyPercentOfTheWork(){hasbeenCalled=true //do other stuff}
val thingThatChildMightWantToAccess=mutableListOf<U>()
fun upDateUsefullThing(){//update thingThatChildMightWantToAccess}
abstract fun fullFillContractToBindViewToItsInformation(t:T,u:U)
abstract fun acknowledgeThatYouKnowAboutUsefullVariable():Boolean
}
You can see from these examples that I'm not being serious. I just really want for their to be a way for me to make my abstract class be more expressive about what it can provide to its children, and what liberties its taken to handle the child's responsibilities.
Your requirement of wanting the "linter" to complain about the fact that some code does not execute some other code (which is just another way of saying make the compiler complain) would require the compiler to know all possible paths of execution a program can take, and then you run into the halting problem.
So, the best you can hope for is run time errors or warnings. Where you implement something that checks that a particular thing has been done and if it has not error.
Or, make sure it happens with something like the template pattern.
Here is a generic inheritance example:
interface LifeCycleAware {
fun stage1()
}
abstract class LifeCycleTemplate : LifeCycleAware {
/**
* Implementations can access this state
*/
protected var stateFromStage1: String? = null
/**
* A template pattern implementation of the lifecycle hook.
*/
override fun stage1() {
startStage1()
doCustomStage1Stuff()
endStage1()
}
protected abstract fun doCustomStage1Stuff()
private fun startStage1() {
stateFromStage1 = "starting-stage-1"
}
private fun endStage1() {
stateFromStage1 = "ended-stage-1"
}
}
Or a more flexible composition example:
typealias InternalStep = (me: LifeCycleComposition) -> Unit
class LifeCycleComposition(
private val customStage1: InternalStep,
private val startStage1: InternalStep = { me -> me.stateFromStage1 = "starting-stage-1" },
private val endStage1: InternalStep = { me -> me.stateFromStage1 = "ended-stage-1" }
) : LifeCycleAware {
/**
* Implementations can access this state
*/
internal var stateFromStage1: String? = null
/**
* A template pattern implementation of the lifecycle hook.
*/
override fun stage1() {
startStage1(this)
customStage1(this)
endStage1(this)
}
}
In a Repository class (see: https://developer.android.com/jetpack/docs/guide), I'm trying to:
1) Read a value from the Room DB
2) Increment the value
3) Write the value back out through the appDao to Room.
I'm pretty sure I can solve this at the Dao level, ie in a Transaction or something, but I'm not sure if that's the right approach. It seems like a pretty simple use case, and the solutions I've come up with seem way more complicated than necessary. I'm wondering if my tenuous handle on Kotlin coroutines is holding me back here.
/* Repository Class*/
fun getCurrentAlarmTime():LiveData<Calendar> {
return Transformations.map(appDao.getProfileData(currentAlarmTime)){ nullableProfileData ->
if (nullableProfileData == null) {
defaultAlarmTime
} else {
nullableProfileData.value.toLongOrNull()?.let { millis ->
getCalendar(millis)
}
}
}
}
fun setCurrentAlarmTime(calendar:Calendar) {
GlobalScope.launch {
appDao.setProfileData(
ProfileData(
currentAlarmTime,
calendar.timeInMillis.toString()
)
)
}
}
fun incrementAlarmTimeBy1Hour() {
// this is what I'm having a problem with, using the fns above.
// I've got a pretty good handle on LiveData,
// Transformations, and MediatorLiveData,
// but I am still stuck.
}
Expected result would be that the time in the database is updated by 1 hour.
I think I figured out something that's not a terrible solution, by reading the reference for Room here: https://developer.android.com/training/data-storage/room/accessing-data
The crux of it is that Room can return LiveData, or it can return what I would call synchronous queries. It's the difference between the following two signatures:
#Query("SELECT * FROM profileData WHERE entry = :entry limit 1")
fun getProfileData(entry: String): LiveData<ProfileData?>
#Query("SELECT * FROM profileData WHERE entry = :entry limit 1")
suspend fun getProfileDataSync(entry: String): ProfileData
The first one you would observe, the second one you could call directly from a coroutine.
Someone should let me know if this is not best practice, but it seems like that reference material above supports it.
To note, I didn't have to put the Room DB in any kind of weird synchronous mode to support this.
What if overload some Kotlin operator and use it like this:
// Inits somewhere before usage.
val someStrFromServer: String?
lateinit var myFieldText: TextView
override fun onStart() {
super.onStart()
myFieldText.text = someStrFromServer / R.string.app_none
}
Operator overloading:
operator fun String?.div(resId: Int): String {
return if (this.isNullOrBlank()) {
context.getString(resId)
} else {
this
}
}
Output if someStrFromServer null:
D/DEBUG: None
Output if someStrFromServer not null:
D/DEBUG: someStrFromServer
Does anyone know, if in Kotlin exists a more efficient and short way to handle this? Perhaps, even more, global, like extension function.
You can do that, but it's not very intuitive because the div is normally used in mathematical calculations only. I'd recommend to use something like
someStrFromServer.takeUnless { it.isNullOrBlank()} ?: context.getString(resId)
Or simplified via extension
fun String?.fallback(resId: Int) = takeUnless { it.isNullOrBlank()} ?: context.getString(resId)
used like this:
myFieldText.text = someStrFromServer.fallback(R.string.app_none)
I'm trying to figure out if something is possible. Generally, what I'm trying to do is get a class type of a subclass from within the companion object of the superclass ... In the snipped below, treat the __ as what I need
companion object
{
fun fromSnapshot(snapshot: DataSnapshot): __
{
val model = snapshot.getValue(__)
model.key = snapshot.key
// ...
return model
}
}
Some background ... DataSnapshot is from Firebase, and snapshot.getValue() takes a Class<T>. If I were trying to create an instance of, say, a TestModel, code would be as follows
companion object
{
fun fromSnapshot(snapshot: DataSnapshot): TestModel
{
val model = snapshot.getValue(TestModel::java.class)
model.key = snapshot.key
// ...
return model
}
}
I'm not really sure if what I'm asking is possible in Kotlin. I'm pretty sure it isn't in Java. I hate to mention it, but in Swift, this would be accomplished with what I call "big-S self," or Self, which is the class type of instance self. If you don't know Swift, self is equivalent to Java and Kotlin's this.
Any help would be hugely appreciated!
From your code, it seems to be a very generic function. It doesn't matter what T is and in which companion object this function lives, so I have another version:
inline fun <reified T : FirebaseModel> DataSnapshot.toModelOfType() =
getValue(T::class.java).also { it.key = this.key}
It can be used like this:
someSnapshot.toModelOfType<SomeFirebaseModel>()
instead of your
FirebaseModel.fromSnapshot<SomeFirebaseModel>(someSnapshot)
or with imports
fromSnapshot<SomeFirebaseModel>(someSnapshot)
I prefer mine because it's shorter than your version without imports and more fluent than your version with imports.
I personally suggest Prefer extension functions over Java style utility functions.
Even though I sat on this for days without posting a question, I figured it out less than an hour after posting this question. This can be accomplished with a reified generic type, which allows for usage of the generic type from within a function, however these can only be used as inline functions. Here's my solution
companion object
{
inline fun <reified T : FirebaseModel> fromSnapshot(snapshot: DataSnapshot): T
{
val model = snapshot.getValue(T::class.java)
model.key = snapshot.key
return model
}
}