The question is in the comment. I want to refer to the outer function append, and not the one that's defined in the StringBuilder, how do I do this?
fun append(c: Char) {
println("TEST")
}
fun sbTest() = with(StringBuilder()) {
for(c in 'A'..'Z') {
append(c) // how do I refer to the append function declared above?
}
toString()
}
I know I can introduce a function reference variable, like this:
val f = ::append
and call f instead of append, but is there another way?
The problem is that anything called within with shadows the outer functions, because this is introduced. The same problem appears if you have a class and a top-level function with a function with the same signature.
The obvious option would just be re-naming it. Also, the function you have there isn't really descriptive compared to what it actually does. But if you for some reason can't rename, there are still other options.
Top-level methods can be referenced by package in Kotlin, for an instance like com.some.package.method. It can also be imported as such, which is the most common way to do it. There are very few methods that are called as com.some.package.method().
Kotlin, like Python, allows as in imports. Which means, you can do this:
package com.example;
// This is the important line; it declares the import with a custom name.
import com.example.append as appendChar; // Just an example name; this could be anything ***except append***. If it's append, it defeats the purpose
fun append(c: Char) {
println("TEST")
}
fun sbTest() = with(StringBuilder()) {
for(c in 'A'..'Z') {
appendChar(c)
}
toString()
}
Alternatively, as I mentioned, you can add the package:
for(c in 'A'..'Z') {
com.example.append(c)
}
val f = ::append is of course an option too, either way, it is still easier to rename the function than create imports with as or constants, assuming you have access to the function (and that it doesn't belong to a dependency).
If your file is outside a package, which I do not recommend you do, you can just declare the import as:
import append as appendChar
You could also use an extension function instead of with(), such as .let{...}.
This will send StringBuilder as an argument to the extension function as it (You can rename it to whatever you want btw):
fun sbTest() = StringBuilder().let{ it ->
for(c in 'A'..'Z') {
// using string builder
it.append(c)
// using your function
append(c)
}
it.toString()
}
The .let{...} function returns your last statement, aka the String from toString(), so your original function would still return it properly. Other functions can return this instead, such as .also{...}
I tend to use extension functions rather than with() as they're more flexible.
See this post to master extension functions: https://medium.com/#elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84
EDIT: Got also{} and let{} mixed up. I switched them
Related
I want to add an ActionListener to a JButton in Kotlin. In Java, I would just write this:
JPanel makeButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
JButton dirButton = new JButton("Change directory");
dirButton.addActionListener(e -> chooseDirectory());
panel.add(dirButton)
return panel;
}
But it's not so simple in Kotlin. I first tried this:
private fun makeButtonPanel() : JPanel {
val panel = JPanel(FlowLayout())
val dirButton = JButton("Choose")
dirButton.addActionListener(e -> chooseDirectory()) // error message here
// ...
}
private fun chooseDirectory() { ... }
But I'm getting this error message:
Type Mismatch
Required: ((ActionEvent!) -> Unit)!
Found: KFunction1<ActionEvent, Unit>
I understand that the ! means that this is a java method with uncertain nullability, but that doesn't help me understand how to write it. All I want it to do is call the chooseDirectory() method. There must be a clean, simple way to do this, but I don't see it.
As you've discovered, you need to use braces ({ }).
This is because braces are a necessary part of defining a lambda in Kotlin. (That differs from languages like Java and Scala, where the necessary part is the -> or => arrow. That's because in Kotlin the arrow is optional if there are one or no parameters; if one, the it keyword is used.)
Without the braces, the code would call your chooseDirectory() function, and try to pass its result to addActionListener() — which obviously wouldn't work.
Braces are also sufficient: they're taken as defining a lambda unless you're giving the body of a function or method or an if/when branch. (Again, this differs from most C/Java-like languages. In Kotlin, if you just want a block scope, you have to use a construct such as run.)
As for the parentheses, they're optional here. You could include them if you wanted:
dirButton.addActionListener({ chooseDirectory() })
But Kotlin has a convention that if a function's last parameter is a function, you can pass it after the parens:
dirButton.addActionListener(){ chooseDirectory() }
And if that would make the parens empty, then you can omit them entirely:
dirButton.addActionListener{ chooseDirectory() }
That's to allow functions that look like new language syntax. For example, you may have met the with function:
with(someObject) {
itsProperty = someValue
}
That's just a perfectly ordinary function, defined in the standard library, and taking a function as its last parameter. Similarly, repeat:
repeat(10) {
// Some code to be run 10 times…
}
There's one further thing worth mentioning here. In Kotlin, lambdas are one way to define functions, which are first-class types and can be defined, passed around, and used just like other types. This differs from Java, which has traditionally used interfaces for those purposes — often interfaces with a Single Abstract Method (‘SAM interfaces’) — and in which lambdas are little more than syntactic sugar for defining an anonymous implementation of such an interface.
As a special case, for interoperability, Kotlin allows a lambda to define an implementation of a Java SAM interface (or, since Kotlin 1.4, of a Kotlin fun interface), instead of a function.
ActionListener is a Java SAM interface, which is why you can use a lambda here.
Okay, I figured it out, and it was pretty simple. I just have to dispense with the parentheses and say
dirButton.addActionListener { chooseDirectory() }
I'm still not clear on when I should use braces instead of parentheses.
I am trying to use the public interface Function (as I learned it in Java) in Kotlin.
For this I created my method
fun foo(input: List<String>, modifier1: Function<List<String>>? = null){
}
as far I remember here I should be able to do modifier1.apply(input)
but seems like it is not possible (it is possible to do modifier1.apply{input} though)
Reading more about it I found this:
Kotlin: how to pass a function as parameter to another?
So I changed my method signature to this:
fun foo(input:String, modifier2: (List<String>) -> (List<String>){
}
Here I am able to do modifier2(input)
and I can call foo this way
service.foo(input, ::myModifierFunction)
where
fun myModifierFunction(input:List<String>):List<String>{
//do something
return input
}
So far this seems possible but it is not acceptable to have the function reference as nullable, is there any way I can do that? or use Function ?
You were using kotlin.Function instead of java.util.function.Function in your first example. Note that the latter takes 2 generic types: 1 for the incoming parameter and 1 for the resulting one.
The apply method you saw is the default Kotlin one: apply, not the one of Java's Function-interface.
If you really want to have the Java-function as nullable type the following should work:
fun foo(input: List<String>, modifier1: java.util.function.Function<List<String>, List<String>>? = null) {
modifier1?.apply(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Kotlin variant for the same:
fun foo(input: List<String>, modifier1: ((List<String>) -> List<String>)? = null) {
modifier1?.invoke(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Maybe also a default function, such as { it } instead of null might better suite your needs? (Java variant would be Function.identity()):
// java modifier1 : Function<List<String>, List<String>> = Function.identity()
// kotlin modifier1 : (List<String>) -> List<String> = { it }
You can make the reference nullable simply with ? — the only wrinkle is that the whole function type needs to be in parens first:
fun foo(input: String, modifier2: ((List<String>) -> List<String>)? = null) {
}
As required, modifier2 is optional; if specified, it may contain null, or it may contain a function taking and returning a list of strings.
As mentioned in another answer, kotlin.Function is not the same as java.util.function.Function — though in practice you shouldn't need to refer to either directly, as the -> notation is simpler.
If you want to pass in a function that takes List<String> as its parameter and returns nothing meaningful, the type for you is Function1<List<String>, Unit>. The method name for invoking a function is invoke(), which you could also do with just regular parentheses, if it wasn't nullable. All in all, your code could look something like this:
fun foo(input: List<String>, modifier1: Function1<List<String>, Unit>? = null) {
modifier1?.invoke(input)
}
The 1 in the typename of Function1 means that it's a one parameter function, there's also Function0, Function2, etc.
The Function type on its own is not something you can use to call that function, as it's an empty marker interface. All functions implement this regardless of how many parameters they have.
I would like to implement custom conversion function of my class Foo to be able to pass it to the function that requres Bar object.
Equivalent C++ construction https://en.cppreference.com/w/cpp/language/cast_operator
class Foo {
operator Bar () {...}
}
Kotlin does not have implicit conversions, as an intentional design decision. You would need to make it explicit. You can do this either putting the burden on the caller, or on the receiver.
For example, if I had:
class One()
class Two()
object Utilities {
fun foo(one: One) {
...
}
}
If I want to pass an instance of Two to foo() I would either:
// add extension function for explicit conversion:
fun Two.toOne(): One { ... convert my instance to other type }
// now caller must convert:
Utilities.foo(myTwo.toOne())
The burden above is on the caller to convert, given this new extension function to do the conversion. This is typical of how Kotlin handles everything in the standard library.
But maybe you want to make it feel more implicit, so you could also add:
// add an extension to the callee, for implicit conversion:
fun Utilities.foo(two: Two) { foo(two.toOne()) }
// now caller doesn't have to convert:
Utilities.foo(myTwo)
Now the caller never sees the conversion, although they have to import your extension function and their IDE hopefully will auto-suggest this for them. So it feels implicit but they had to choose to use that extension, which is easy to do.
Notice that none of the extension functions above needed any modifications to the actual classes. These extensions can be imported individually or in the whole package import. They can be done independently from classes you do or do not control. They can be done from anywhere at any time.
Final code, in its entirety:
// original classes
class One()
class Two()
object Utilities {
fun foo(one: One) {
...
}
}
// extensions
fun Two.toOne(): One {
// ... convert my instance to other type
}
fun Utilities.foo(two: Two) { foo(two.toOne()) }
And now you can use either model as your code style desires.
Code
import kotlin.reflect.full.*
class FooBar(val bar: String)
fun FooBar.baz(): Unit {println(this.bar)}
fun main(args: Array<String>) {
FooBar::class.declaredMemberExtensionFunctions.forEach {
println(it)
}
FooBar::class.memberExtensionFunctions.forEach {
println(it)
}
}
Output is empty
This is because declaredMemberExtensionFunctions only returns extension functions that are declared inside a class (as seen in the docs) and FooBar.baz() is a top level declaration (So it is not declared inside FooBar.
class FooBar(val bar: String) {
fun FooBar.baz(): Unit {
println(this.bar)
}
}
While I imagine this is not what you want, structuring the extension function like this would make your main method output lines.
TLDR: You aren't going to be able to do this. Because extension functions can be declared everywhere, you are limited in what the reflection system can do for you.
There is a thread on kotlinlang.org that covers this exact question and why it is not possible.
Essentially, Kotlin's declaredMemberExtensionFunctions function is able to list extension functions which are declared as part of the class, not externally. The docs state:
Returns extension functions declared in this class.
And of course, memberExtensionFunctions behaves similarly:
Returns extension functions declared in this class and all of its superclasses.
Here's what #Yole says in that thread as to why this is not possible:
The task of finding all extension functions for Foo is equivalent to finding all methods which have Foo as the first parameter. Neither of these is possible without accessing every single class in your application through reflection.
#Yole is on here, he might be able to provide a more authoritative answer for you.
I was reading about Kotlin and did not quite get the idea
from What I understood extension function gives ability to a class with new functionality without having to inherit from the class
and what is receiver the same except it can be assigned to variable
Is there anything else about it?
Can someone give some examples on it
Extension functions:
Like Swift and C#, Kotlin provides the ability to extend a class with new functionality without having to modify the class or inherit from the class.
You might wonder why? Because we cannot edit and add functions to the language or SDK classes. So we end up creating Util classes in Java. I believe all the projects have a bunch of *Utils classes to put the helper methods that are used at multiple places in the code base. Extensions functions help to fix this Util problem.
How do we write a helper method in Java to find whether the given long value refers to today?
public class DateUtils {
public static boolean isToday(long when) {
// logic ...
}
}
And we call that method by passing the long value as an argument:
void someFunc(long when) {
boolean isToday = DateUtils.isToday(when);
}
In Kotlin, we can extend the Long class to include the isToday() function in it. And we can call the isToday() function on the Long value itself like any other member functions in the class.
// Extension function
fun Long.isToday(): Boolean {
// logic ...
}
fun someFunc(time: Long) {
val isToday = time.isToday()
}
Compared to the Util methods, Kotlin provides a much richer syntax using the Extension functions.
This improves the readability of the code which in turns improves its maintainability. And we get a little help from the code completion of the IDE. So we don't have to remember which Util class to use for the desired function.
Under the hood, Kotlin compiler generates the static helper methods as though we had written them as Java static Util methods. So we get this nice and richer syntax in Kotlin without sacrificing any performance.
Similar to functions, Kotlin also supports extension properties where we can add a property to an existing class.
Higher order functions:
A higher-order function is a function that takes functions as parameters, or returns a function.
Lets look at how a higher order function is written.
fun execute(x: Int, y: Int, op: (Int, Int) -> Int): Int {
return op(x, y)
}
Here the third parameter ( op ) is a function and so it makes this function a higher order function. The type of the parameter op is a function that takes 2 Ints as parameter and returns a Int.
To invoke this Higher order function, we can pass a function or a lambda expression:
execute(5, 5) { a, b -> a + b }
Receiver (or Function literal with Receiver or Lambda with Recevier):
A Higher order function that takes an extension function as its parameter is called Lambda with Receiver.
Let's look at the implementation of the apply function which is available in the Kotlin standard library.
inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
The function we pass to this apply function is actually an extension function to the type T. So in the lambda function, we can access the properties and the functions of the type T as though we are writing this function inside class T itself.
Here the generic type T is the receiver and we are passing a lambda function, hence the name Lambda with Receiver.
Another Example:
inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
beginTransaction()
try {
func()
setTransactionSuccessful()
} finally {
endTransaction()
}
}
Here, the inTransaction() is an Extension function to the SQLiteDatabase class and the parameter of the inTransaction() function is also an extension function to the SQLiteDatabase class. Here SQLiteDatabase is the receiver, for the lambda that is passed as the argument.
To invoke that function:
db.inTransaction {
delete( ... )
}
Here the delete() is the function of the SQLiteDatabase class and since the lambda we pass is an Extension function to the receiver SQLiteDatabase we can access the delete function without any additional qualifiers with it, as though we are calling the function from inside the SQLiteDatabase class itself.
While #Bob's answer is far more informative on Kotlin than could I hope to be, including extension functions, it doesn't directly refer to the comparison between "function literals with receiver" as described in https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver and extension functions (https://kotlinlang.org/docs/reference/extensions.html). I.e. the difference between:
val isEven: Int.() -> Boolean = { this % 2 == 0 }
and
fun Int.isEven(): Boolean = this % 2 == 0
The receiver part of the name refers to both of these syntaxes receiving the base Int argument as this.
As I understand it, the difference between the two is simply between one being an expression confirming to a function type and the other a declaration. Functionally they are equivalent and can both be called as:
when { myNumber.isEven() -> doSomething(myNumber) }
but one is intended for use in extension libraries, while the other is typically intended for use as an argument for a function with a function-type parameter, particularly the Kotlin builder DSLs.