What is the purpose of kotlin contract - android

Was reading the apply function code source and found
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
and contract has an empty body, experimental
#ContractsDsl
#ExperimentalContracts
#InlineOnly
#SinceKotlin("1.3")
#Suppress("UNUSED_PARAMETER")
public inline fun contract(builder: ContractBuilder.() -> Unit) { }
what is the real purpose of contract and is it here to stay in the next versions?

What is the real purpose of contract
The real purpose of Kotlin contracts is to help the compiler to make some assumptions which can't be made by itself. Sometimes the developer knows more than the compiler about the usage of a certain feature and that particular usage can be taught to the compiler.
I'll make an example with callsInPlace since you mentioned it.
Imagine to have the following function:
fun executeOnce(block: () -> Unit) {
block()
}
And invoke it in this way:
fun caller() {
val value: String
executeOnce {
// It doesn't compile since the compiler doesn't know that the lambda
// will be executed once and the reassignment of a val is forbidden.
value = "dummy-string"
}
}
Here Kotlin contracts come in help. You can use callsInPlace to teach the compiler about how many times that lambda will be invoked.
#OptIn(ExperimentalContracts::class)
fun executeOnce(block: ()-> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
#OptIn(ExperimentalContracts::class)
fun caller() {
val value: String
executeOnce {
// Compiles since the val will be assigned once.
value = "dummy-string"
}
}
is it here to stay in the next versions?
Who knows. They are still experimental after one year, which is normal for a major feature. You can't be 100% sure they will be out of experimental, but since they are useful and they are here since one year, in my opinion, likely they'll go out of experimental.

Related

coroutines.delay vs flow.debounce for input in EditText

Unexpectedly, but it seems, this question was never asked before (at least I didn't find it).
So, if we have some search EditText and want to send search requests to server, when user inputs text. Strait approach will lead to the case, when we send request to server for each typed symbol. To escape this case, we need to add some logic to wait until user stops typing search query. My question is applicable for app with coroutines.
If we use coroutines, for now there is two ways to implement user input delay. First is to use coroutines.delay function, it is presented here. Its main idea is to launch and delay coroutine
fun <T> debounce(
waitMs: Long = 300L,
coroutineScope: CoroutineScope,
destinationFunction: (T) -> Unit
): (T) -> Unit {
var debounceJob: Job? = null
return { param: T ->
debounceJob?.cancel()
debounceJob = coroutineScope.launch {
delay(waitMs)
destinationFunction(param)
}
}
}
Second way is to use new function flow.debounce, it is presented here. Its main idea is we make flow from EditText input and then apply debounce to it
#ExperimentalCoroutinesApi
#CheckResult
fun EditText.textChanges(): Flow<CharSequence?> {
return callbackFlow {
checkMainThread()
val listener = doOnTextChanged { text, _, _, _ -> trySend(text) }
awaitClose { removeTextChangedListener(listener) }
}.onStart { emit(text) }
}
editText.textChanges()
.debounce(300)
.onEach { ... }
.launchIn(lifecycleScope)
My question is about differences in this two approaches (except they use different technologies) and about advantages and disadvantages of both of them. Hope someone is able to clarify the difference.

How to make an inline function remove itself when its being used as a listener in kotlin

I have hit a wall with this one and I can't find any question with a solution for this here in SO.
I am using a PagingAdapter method, from Google's Paging library, that receives an inline function as a listener:
fun addLoadStateListener(listener: (CombinedLoadStates) -> Unit) {
differ.addLoadStateListener(listener)
}
And then to remove the listener they provide the following method
fun removeLoadStateListener(listener: (CombinedLoadStates) -> Unit) {
differ.removeLoadStateListener(listener)
}
And I am using it like this
myPagingAdapter.addLoadStateListener { it: CombinedLoadStates ->
myPagingAdapter.removeLoadStateListener(this)
}
I know the above does not work, but it worked when the file was written in java since it had a correct reference to itself inside its own function. However, in Kotlin I cannot find a way to do this at all. I tried turning into an anonymous function, but it still won't pass the correct context
myPagingAdapter.addLoadStateListener { fun(it: CombinedLoadStates) ->
myPagingAdapter.removeLoadStateListener(this)
}
At this point I have no idea how I can remove an inline function that can't reference itself, and I cannot find any documentation with a solution for this anywhere.
How can I remove in kotlin an inline function by referencing itself?
If I understand correctly, you need a reference of inline function which was passed in addLoadStateListener so you can pass in removeLoadStateListener.
You can try this
myPagingAdapter.addLoadStateListener(object : (String) -> Unit {
override fun invoke(p1: String) {
myPagingAdapter.removeLoadStateListener(this)
}
})
You can create a local function to reference itself:
fun myFun(CombinedLoadStates): Unit {
myPagingAdapter.removeLoadStateListener(::myFun)
}
myPagingAdapter.addLoadStateListener(::myFun)

How to declare an interface that works with lambda? [duplicate]

This question already has answers here:
Lambda implementation of interface in kotlin
(5 answers)
Closed 4 years ago.
I declared a simple interface like this:
interface OnSomethingReadyListener {
fun onSomethingReady()
}
And of course a setter:
private val onSomethingReadyListeners = ArrayList<OnSomethingReadyListener>()
fun addOnSomethingReadyListener(callback: OnSomethingReadyListener) {
onSomethingReadyListeners.add(callback)
}
But then I found that I cannot use lambda:
something.addOnShopDataReadyListener { progressbar.visibility = View.GONE }
IDE gave me an error:
Type mismatch.
Required: SomeClass.OnSomethingReadyListener
Found: () -> Unit
Suppose I want to stick to using lambda instead of anonymous class (object : OnSomethingReadyListener {...}). How should I declare OnSomethingReadyListener?
SAM (single abstract method) conversion is only support for Java interfaces, not Kotlin interfaces.
The documentation states this reasoning:
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
KT-7770 requests this functionality, if you want to track whether it is being considered or not.
The recommended way to achieve what you want is to replace the OnSomethingReadyListener with a parameter of type () -> Unit like so:
private val onSomethingReadyListeners = ArrayList<() -> Unit>()
fun addOnSomethingReadyListener(callback: () -> Unit) {
onSomethingReadyListeners.add(callback)
}
You can then invoke those listeners with something like
onSomethingReadyListeners.forEach { it.invoke() }
You have to declare the function as this:
fun addOnSomethingReadyListener(block: (OnSomethingReadyListener) -> Unit)
And then you can call it as follow:
addOnSomethingReadyListener {
// TODO
}

How to pass null to an Observable with nullable type in RxJava 2 and Kotlin

I initialize my variable like this:-
val user: BehaviorSubject<User?> user = BehaviorSubject.create()
But I can't do this. IDE throws an error:-
user.onNext(null)
And doing this, IDE says u will never be null:-
user.filter( u -> u!=null)
As Guenhter explained, this is not possible. However, instead of proposing the null-object pattern, I'd recommend an implementation of the Optional type:
data class Optional<T>(val value: T?)
fun <T> T?.asOptional() = Optional(this)
This makes your intent much clearer, and you can use a destructuring declaration in your functions:
Observable.just(Optional("Test"))
.map { (text: String?) -> text?.substring(1)?.asOptional() }
.subscribe()
Using the null-object pattern here can cause more bugs than it solves.
If you use rxkotlin/rxjava 2.0 (I assume so) than the answer is: you can't. The reason is explained here.
This is a break of the interface. Have a look at the Observable Interface
public interface Observer<T> {
/** ... */
void onSubscribe(#NonNull Disposable d);
/** ... */
void onNext(#NonNull T t);
/** ... */
void onError(#NonNull Throwable e);
/** ... */
void onSubscribe(#NonNull Disposable d);
/** ... */
void onNext(#NonNull T t);
/** ... */
void onError(#NonNull Throwable e);
...
The #NonNull will be considered by the Kotlin compiler and therefore you CAN'T pass null.
Even if you could, the onNext would immediately throw an error:
#Override
public void onNext(T t) {
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
...
}
If you really need such a thing as null you have to fake it. e.g. by creating a static object of User which represents your null-element.
e.g.
data class User(val username, val password) {
companion object {
val NULL_USER = User("", "")
}
}
...
val user = BehaviorSubject.create<User>()
...
user.onNext(User.NULL_USER)
...
user.filter { it !== User.NULL_USER }
But if is somehow possible, try to avoid the null concept and maybe think of another solution where this isn't needed.
Thank you very much for all your answers but I ultimately went with this solution:-
class UserEnvelope(val user:User?) {}
And using this in the observables.
This best suited my requirements.
I am new to Kotlin so I don't know how to use Optionals. But from what I understand, I would have to typecast it to User type everytime I need to observe the values right?
To implement the solution mentioned in the nhaarman's answer, you can use the util class Optional (doc) from the Android SDK which was added in API level 24.
If your app's minSdkVersion less than 24 then you still need to implement it by yourself.
Since RxJava 2 does not support null values, there are some other acceptable solutions you can use:
Work with a custom or third party wrapper library of Optionals like some of the posted answers suggest. When I got rid of Java in favour of Kotlin, Optionals went away in the same package since Kotlin per se supports nullability as part of its type System. Just by this change the code was much more clearer, and I personally don't want to get Optionals back in my code as long as I can avoid them.
Emit Any class instances with your subject type. For example you could create an Empty.INSTANCE enum class which would emulate the null value and then filter by the enum class.
The last one is the one I use and prefer being a variant of the previous solution and is based on specialisations. Our friends of JetBrains always emphasise that classes are very cheap in Kotlin, so this would be a quick example to distinguish logged users and not logged ones:
abstract class SessionUser
sealed class LoggedUser(val username: String, val password: String) : SessionUser()
sealed class LogoutUser : SessionUser()
private val user = BehaviorSubject.create<SessionUser>()
private val loggedUser =
user.filter { it is LoggedUser }.cast(LoggedUser::class.java)
fun login(username: String, password: String) {
user.onNext(LoggedUser(username, password))
}
fun logout() {
user.onNext(LogoutUser())
}
I've taken an approach similar to Optional<User> and UserEnvelope. I make a simple User class and a ReifiedUser class that inherits from it. The User class has a companion object that has a NONE instance. The BehaviorSubject is instantiated with the User.NONE instance. It looks something like this:
open class User {
companion object {
val NONE = User()
}
}
class ReifiedUser(
#field:JsonProperty(J.FirstName) val firstName: String,
#field:JsonProperty(J.LastName) val lastName: String
) : User()
My BehaviorSubject is instantiated like this:
val activeUser: BehaviorSubject<User> = BehaviorSubject.createDefault(User.NONE)
And wherever I need to use activeUser I either flatMap it to Observable.empty() if it's NONE or just figure out what it is and what to do in the subscriber.
I don't like mixing java Optional with kotlin nullable because mixing map and let gets really confusing and ugly. This way it's very obvious what's going on.
I think it makes more sense to write a container class such as Result. An example of that would be
data class Result<T>(value: T?, error: Throwable?)
Usage
Observable.create { observer ->
upstreamService.listen(object: UpstreamListener {
onSuccess(data: User) {
observer.onSuccess(Result(data))
}
onError(exception: Throwable) {
observer.onSuccess(Result(null, exception))
}
}
}

Unit test on Kotlin Extension Function on Android SDK Classes

Kotlin extension function is great. But how could I perform unit test on them? Especially those that is of Android SDK provided class (e.g. Context, Dialog).
I provide two examples below, and if anyone could share how I could unit test them, or if I need to write them differently if I really want to unit test them.
fun Context.getColorById(colorId: Int): Int {
if (Build.VERSION.SDK_INT >= 23)
return ContextCompat.getColor(this, colorId)
else return resources.getColor(colorId)
}
and
fun Dialog.setupErrorDialog(body : String, onOkFunc: () -> Unit = {}): Dialog {
window.requestFeature(Window.FEATURE_NO_TITLE)
this.setContentView(R.layout.dialog_error_layout)
(findViewById(R.id.txt_body) as TextView).text = body
(findViewById(R.id.txt_header) as TextView).text = context.getString(R.string.dialog_title_error)
(findViewById(R.id.txt_okay)).setOnClickListener{
onOkFunc()
dismiss()
}
return this
}
Any suggestion would help. Thanks!
The way I'm testing extension functions on Android classes at the moment is by mocking the Android class. I know, this is not an optimal solution as it mocks the class under test and requires certain knowledge about how the function works (as it is always the case when mocking), but as extension functions are internally implemented as static functions I guess it's acceptable until someone comes up with something better.
As an example consider the JsonArray class. We've defined an extension function for receiving the last item's index:
fun JSONArray.lastIndex() = length() - 1
The according test (using the Spek test framework and mockito-kotlin) looks like this.
#RunWith(JUnitPlatform::class)
object JsonExtensionTestSpec : Spek({
given("a JSON array with three entries") {
val jsonArray = mock<JSONArray> {
on { length() } doReturn 3
}
on("getting the index of the last item") {
val lastIndex = jsonArray.lastIndex()
it("should be 2") {
lastIndex shouldBe 2
}
}
}
given("a JSON array with no entries") {
val jsonArray = mock<JSONArray>({
on { length() } doReturn 0
})
on("getting the index of the last item") {
val lastIndex = jsonArray.lastIndex()
it("should be -1") {
lastIndex shouldBe -1
}
}
}
})
The difficulty with your functions is, that they also use Android classes internally. Unfortunately I don't have a solution for this right now.

Categories

Resources