Passing a lambda to the last parameter
In Kotlin, there is a convention that if the last parameter of a
function accepts a function, a lambda expression that is passed as the
corresponding argument can be placed outside the parentheses:
val product = items.fold(1) { acc, e -> acc * e }
What is the purpose of this syntax?
This syntax gives Kotlin great DSL capabilities, it makes functions look like language constructions. For example:
with(car) {
startUp()
goToDestination()
}
Here with looks like it is language construction, whereas it is a simple function, receiving lambda as the last parameter.
And this leads to such elegant things like Kotlin HTML DSL
Related
I've seen people using ViewModelProvider[Someclass::class.java] instead of ViewModelProvider.get(Someclass::class.java), and it compiles in Android Studio. The problem is that I couldn't find any documentation of such usage online.
With kotlin you can add operator modifiers to your function. So if you have some class with a get function and you might want to access it with [], like an array or map, you could add operator modifier.
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
So this only works for functions with name get or set!
class Provider {
operator fun get(key: String)
operator fun set(key: String, value: String) { ... }
}
Then you can call the function like:
Provider().get("key") // IDE hint: should be replaced with indexing operator
Provider()["key"] // calls get()
Provider().set("key", "value") // IDE hint: should be replaced with indexing operator
Provider()["key"] = "value" // calls set()
Reference
See Kotlin Operator overloading
Kotlin allows operator overloading by marking a function as an operator function. The square brackets notation is one of these operators (indexed access operator).
Kotlin automatically interprets Java functions as operator functions if their name and signature match the requirements of a Kotlin operator function. In this case, it interprets functions named get as an "indexed access operator" if they return something, which allows you to use square bracket notation.
ViewModelProvider[Someclass::class.java] is a shorter version of ViewModelProvider.get(Someclass::class.java) there is no differences.
Hi I am making a app with Kotlin and I found that I can both use
textView.setText(str)
and
textView.text = $str
I wanna know what I should use and the differences between them.
Thank you.
They're the same in most cases, basically Kotlin generates a synthetic property for the class attributes based on their getter, which you can use to assign values to and get values from.
//So, for most cases
textView.setText("some value");
//Is the same as
textView.text = "some value"
//The second is simply shorter and is the 'kotlin way' of assigning values
Now, here's the catch -
In most cases, this works fine. But, as mentioned, the synthetic property is generated from the getter, if there is a setter as well, then issues arise. The reason is that the getter and the setter may have different types. For example, EditText has Editable getter, now, kotlin creates a synthetic property text of the type Editable.
editText.setText("some value"); //Works
editText.text = "some value" //Won't work, will show an error stating that expected type is Editable
textView.setText(str) and textView.text = $str, does the same job of setting the specified str to TextView. The only difference I can come up with is,
textView.setText(str) // old Java way of setting Text where method setText(str) was being called.
textView.text = $str //new Kotlin way of setting Text where instead of a method, a synthetic property is being called.
As in the Kotlin, you are not using findViewById
so to access your textView, import statement must be like this
import kotlinx.android.synthetic.main.<layout>.*
And textView.text = $str is the Synthetic Property access provided by Kotlin Plugin for android
You can use both, not much difference in the usability, but for the easier code writing
this would be better
For more information, read this https://kotlinlang.org/docs/tutorials/android-plugin.html
Both works the same way.
Java Convention
textView.setText(“…”)
Kotlin Convention
textView.text=”…”
“Methods that follow the Java conventions for getters and setters (no-argument methods with names starting with get and single-argument methods with names starting with set) are represented as properties in Kotlin.”- documentation
thus textView.text=”…” instead of textView.setText(“…”) if you are using Kotlin to follow Kotlin Conventions.
Ref - Begin Kotlin; from an Activity, a Button and a TextView
The method setText() and getText() are called setters and getters, they are automatically generated in kotlin.
class ClassName{
var name: String= "some_value"
}
You can use the name property directly with the object of the class or you can also use the auto-generated setter method.
class Another{
var c = ClassName()
c.name = "value"
c.setName("value")
}
But if a property starts with a val instead of var then it is immutable and does not allow a setter.
In case you want to read further:-
Setters and getters in kotlin
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'm new to Kotlin
I used this code for opening another activity:
startActivity(Intent(this,IntroAndLang::class.java))
current activity and target activity are written in Kotlin
I can't understand why there is not single : instead of :: at IntroAndLang::class.java
:: is used for Reflection in kotlin
Class Reference val myClass = MyClass::class
Function Reference this::isEmpty
Property Reference ::someVal.isInitialized
Constructor Reference ::MyClass
For detailed reading Official Documentation
:: converts a Kotlin function into a lambda.
Let's say you have a function that looks like this:
fun printSquare(a: Int) = println(a * 2)
And you have a class that takes a lambda as a 2nd argument:
class MyClass(var someOtherVar: Any, var printSquare: (Int) -> Unit) {
fun doTheSquare(i: Int) {
printSquare(i)
}
}
How do you pass the printSquare function into MyClass? If you try the following, it wont work:
MyClass("someObject", printSquare) //printSquare is not a LAMBDA, it's a function so it gives compile error of wrong argument
So how do we CONVERT printSquare into a lambda so we can pass it around? Use the :: notation.
MyClass("someObject",::printSquare) //now compiler does not complain since it's expecting a lambda and we have indeed converted the `printSquare` FUNCTION into a LAMBDA.
Also, please note that this is implied... meaning this::printSquare is the same as ::printSquare. So if the printSquare function was in another class, like a Presenter, then you could convert it to lambda like this:
Presenter::printSquare
UPDATE:
Also this works with constructors. If you want to create the constructor of a class and then convert it to a lambda, it is done like this:
(x, y) -> MyClass::new
this translates to MyClass(x, y) in Kotlin.
As stated in the docs this is a class reference:
Class References:
The most basic reflection feature is getting the runtime reference to a Kotlin class. To obtain the reference to a statically known Kotlin class, you can use the class literal syntax:
val c = MyClass::class
//The reference is a value of type KClass.
Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the .java property on a KClass instance.
It’s also the syntax for method references as in this simple example:
list.forEach(::println)
It refers to println defined in Kotlin Standard library.
Since kotlin 1.1, in addition to class, function, property and constructor references as stated above, '::' can also be used to obtain the bound references to all of the above.
For instance, using '::class' could be used to get the exact class of a particular object despite the type of the receiver as below...
val widget: Widget = ...
assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
widget::class returns the exact class of the object 'widget' as either 'GoodWidget' or 'BadWidget' despite the type of the receiver expression (i.e 'Widget' as declared initially)
More info at https://kotlinlang.org/docs/reference/reflection.html
For one permission I can use permissionsdispatcher in java and kotlin - but when it comes to multiple permissions like this:
#NeedsPermission({Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH})
I get a problem on kotlin - it does not accept more than one parameter there - works fine with java
In Java the {} represents creating an array, and in this context in Kotlin the {} is accidentally creating a lambda expression and it cannot be determined what you intend because the code inside the lambda is invalid.
So you are saying #NeedsPermission(someFunctionReferenceThatIsInvalid) instead of passing in an array of permissions as #NeedsPermission(array)
In the annotation the array is being treated as a vararg so you can just list the elements:
#NeedsPermission(Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH)
If it were being treated as an array, you would use the arrayOf function:
#NeedsPermission(arrayOf(Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH))
The examples creating an array and then using the * spread operator are basically doing and then undoing the array and it is not necessary.
#NeedsPermission(arrayOf(Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH))
In java #NeedsPermission({...}) the curly brackets {...} is just a shorthand for creating an array. In kotlin you must explicitly say that it is an array, because {} is reserved for lambda expressions.