I am learning how to use the coroutines in kotlin. looking at some examples in the internet i found that within the context f the also operator the reference
it
is used. i could not find any explanation about the meaning of
it
please provide some brief explanantion about what does "it" mean
when you use the also method, it has 1 parameter.
Think of it in Java kinda like this:
foo.also(int it) {
// do stuff
}
In Kotlin, the it parameter is implicit (sometimes you might want to use it sometimes you don't).
If you want to rename it to something more readable you can
foo.also { newName ->
// do stuff with newName
}
Or just use it like it is
foo.also {
// do stuff with $it
}
So therefore when you are using a method (or a closure/lambda) if it has 1 parameter, then the implicit name of that parameter is always it.
Basically it represents the lambda parameter
let's say you want to perform anything on the variable but do to check the nullity first, you can do it like
var str:String?=null // str is of string type
now you can use it fail safe
str?.let{it:String// youll see like this
// now you can access str as **it**
}
it is the implicit name of a single parameter
For more information about it and this in scoping functions like also
Related
This might be a very silly question, but I am logging the methods that are triggered in my app as strings. When an issue is submitted, I would like to automatically input the text of the strings as parameters for methods. E.g:
For method:
fun assignPot(potType: PotType, ball: DomainBall, action: PotAction) {...}
I'd like to somehow call method:
assignPot(FOUL(2, BLUE(5), SWITCH))
From String:
"FOUL(2, BLUE(5), SWITCH)"
The only workaround I can think of is to split the string and create a when -> then function to get actual classes from strings, but I wondered if there's a more concise way for this.
This is not what you want to do. You should design your app in a way that prevents users from providing input similar to actual code.
However, you can achieve this. Complex parsings like this oftenly use regex-based approaches.
As you said, you should map your string part to class. If your PotType is enum, you can do something like
val re = Regex("[^A-Za-z\s]")
val reNumbers = Regex("[^0-9\s]")
// get classes
val classNames = originalString.replace(re, "").split(" ")
// get their constructor numerical arguments
val classArgs = originalString.replace(reNumbers, "").split(" ")
After that you can implement mapping with when expression. You probably will use some collection of Any type.
As you see, this sadly leads you to parsing code by code. Concise way to solve is to implement your own script compiler/interpreter and use it in your application :) That will later lead you to dealing with security breaches and so on.
If you are logging problematic method calls and want to repeat them immediately after issue is submitted, you probably want to programatically save the calls to lambdas and call them when you receive an issue log.
I must be doing something wrong with Kotlin implementation of view models
I have a view model that has a function to retrieve youtube video id from url.
fun getYoutubeVideoId(url: String): String?{
return "([a-zA-Z0-9_-]{11})".toRegex().find(url)?.value
}
I feel like I'm always in catch 22 because I use this function in a fragment inside with LiveData observable, which forces me to to ? on objects, which then forces me to have return type with ?, which then tirggers if statements to check if objects aren't null.
Here is the vm var
val streamUrl= mainState.getOrNull { it?.account?.streamUrl ?: 0}.distinctUntilChanged()
Here is my shortened observable
streamUrl.observe{
playVideo(getYoutubeVideoId(it))
}
The error from above statement is that it
Requires a String and I'm passing Any
Return should be String and its String?
I'm running around to make sure the types match and its always something not matching or being right. I think I could setup another streamUrl variable under the viewModel besides the observable, but I feel like I should be able to just do it of a single variable.
I hope this makes sense.
So the first thing to embrace with kotlin is: Null Safety.
Null Safety does not mean that you do not get nulls.
It means, that if something is possibly null, the compiler forces you to think about it and handle it at a point that makes sense. If you don't, you potentially get the notorious NullPointerException at an unexpected and possibly ugly point of execution.
So, to eliminate the ? think about where you want to handle the possibility of it being null -> check it -> handle it in an elegant way, and then safely pass the checked result without a ? to the rest of your code.
We are trying to understand calling a function in Kotlin
The function looks like this
fun onSIMPLE(view: View){
val snack = Snackbar.make(view,"This is a simple Snackbar", Snackbar.LENGTH_LONG)
snack.show()
}
And the call is made this way
btnSB2.setOnClickListener {onSIMPLE(it)}
What we do not understand is how does one know to use the keyword "it"?
Who ever created the keyword "it" must have never searched the Web
We plugged every reasonable keyword in the ( ) to solve the issue
YES we also looked at the documentation
Is there a better way to construct the function or make the call?
it is the implicit name for a single parameter lambda. You can override as you wish, e.g:
btnSB2.setOnClickListener { view -> onSIMPLE(view)}
setOnClickListener expects a lambda as a parameter, using a Java-like approach, this should look like this:
btnSB2.setOnClickListener({
v:View -> onSIMPLE(it)
})
Also, if the lambda is the last parameter for a given function, it can be specified outside of the parenthesis, which would look like this:
btnSB2.setOnClickListener {
v:View -> onSIMPLE(it)
}
It is common for lambda functions to have a single parameter. For these functions, Kotlin maintains the it keyword. Knowing this, the code becomes:
btnSB2.setOnClickListener {
onSIMPLE(it)
}
I have a model with an optional higher-order function (() -> Unit)?
When I want to call that function, I'm wondering, how can I call it even been an optional.
I know this works
model.action?.invoke()
There is something similar to Swift?, where I could do:
model.action?()
I know, I can do too:
model.action?.let { action() }
Maybe this last one is the "better" way to go.
Do you know some "better" way?
Thanks
It's a matter of one's personal preference, but I'd stay with the first variant, i.e.
model.action?.invoke()
Simply because it's just the safe call of invoke operator and it does not have the burden of adding higher-level function (i.e. let) into the expression.
Btw, in some cases if you write something like model.action?.let { it() } in Idea (at least it works for Android Studio which is based on Idea), you'll get a warning saying that let is useless here and you can safely replace it with the plain safe call.
You may use the standard library function let as follows:
val actionResult = model.action?.let { it() }
Note that the receiver of let (model.action) is exposed as it inside the lamda.
Alternatively, and preferably IMO, invoke the function like this:
model.action?.invoke()
If the function returns unit, I’d use also, not let. The former is a side-effecting construct, the latter for returning a value.
In java methods everything is passed-by-value so i can change the object attributes passed to the method and expect that the original object attributes are changed. but in this method i get different result:
I have this method:
public Observable<Menu> makeMenu(Menu menu, NumberSettingChanges.MenuChanges changes) {
// Start flow with added and edited extensions
return Observable.from(changes.added.entrySet())
.mergeWith(Observable.from(changes.edited.entrySet()))
//Upload announcement voices or do nothing if extension is not an announcement
.flatMap(e -> {
if (AppTypeContract.APP_TYPE_ANNOUNCEMENT.equals(e.getValue().type)) {
return mMediaManager.uploadAsync(e.getValue().config.localPrompt)
.doOnNext(response -> {
//Update extension prompt with the storage path.
menu.config.extensions.get(e.getKey()).config.prompt = response.mPath;
menu.config.extensions.get(e.getKey()).config.localPrompt = "";
})
.flatMap(response -> Observable.just(e));
} else {
return Observable.just(e);
}
}
)
}
and i manipulate menu attributes in the flatmap:
menu.config.extensions.get(e.getKey()).config.localPrompt = "";
I call the method in the same class:
public Observable<NumberSetting> saveSettings(NumberSetting o, NumberSetting n) {
NumberSettingChanges changes = compareNumberSetting(o, n);
return makeMenu(n.day, changes.day)
.mergeWith(makeMenu(n.night, changes.night));
}
and finally:
saveSettings(ns, mNumberSettingNew).subscribe();
What i expect is that the mNumberSettingNew.menu.config.extensions.get(e.getKey()).config.prompt is changed but no change is happening after this call and the mNumberSettingNew has no change at all.
Note that i am sure that changing prompt line is done in the debug.
I don't think I could explain Java's parameter semantics any better than (or even half as good as) the link you referenced in your first paragraph so I won't try. The main point is: Everything in Java is passed by value (i. e. copied) but with objects what is copied is not the object itself but the reference to the object. So in other words the reference is passed by value.
So with respect to your particular problem: Yes, if you pass a reference to a mutable object to some rx-java code that reference will point to the same instance of the object. If you mutate the instance then the caller code will also be able to see the changes because they were made on the same instance. That's because rx-java is still only Java and cannot change the language semantics on that level.
Without seeing the whole code I am unsure what could be the problem here... When are you checking whether mNumberSettingsNew actually has the changes you were making in your doOnNext? If you check that immediately after saveSettings(ns, mNumberSettingNew).subscribe(); your uploadAsync may not have returned yet. You could try adding an actual Subscriber in your subscribe and check the result there.
On a more general note, I think you should try to avoid side-effects like this as much as you can when using rx-java. Your case - taking an input object, applying a set of (possibly asynchronous) changes to that object, and waiting for the changed output object - is a bit tricky, but I think it could be done with scan. Maybe something vaguely like this:
Observable.from(changes.added.entrySet())
.mergeWith(Observable.from(changes.edited.entrySet()))
.scan(menuBeforeAnyChanges, new Func2<Menu, Change, Menu>() {
public Menu call(final Menu previousVersionOfTheMenu, final Change nextChange) {
// since I don't know of a version of scan that can return
// an Observable you would I think you would have to adapt
// your code in here to be fully synchronous - but of
// course the scan itself could run asynchronously
final newVersionOfTheMenu = previousVersionOfTheMenu.applyChange(nextChange);
return newVersionOfTheMenu;
}
)
This would take the original Version of the menu, consecutively apply all the changes from added and edited and /emit/ every updated version of menu. So you would not have any side effects but simply subscribe to that observable with a Subscriber<Menu> and then take the last() Menu and that would be the one with all changes applied.
EDIT: Oh, I just saw that there is another method called reduce that does just that: first scan and then last or takeLast.