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.
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 have a Kotlin function with this signature:
fun registerDisposer(obj: Any, disposer: Closeable)
What the function does is attach disposer to a phantom reference and arrange it to be closed when obj is garbage-collected (i.e. when the phantom reference object is enqueued). The class of obj is supposed to call it something like this:
class Holder(private val res1: Closeable, private val res2: Closeable) {
init {
registerDisposer(this, object: Closeable {
private val res1 = this#Holder.res1
private val res2 = this#Holder.res2
override fun close() {
res1.close()
res2.close()
}
})
}
}
(Let’s ignore whether this is a good idea to rely on this with general Closeables; the actual resource in question is a pointer managed by native/JNI code – I am trying to follow Hans Boehm’s advice. But all of this is not particularly relevant for this question.)
I am worried that this design makes it too easy to inadvertently pass an object that captures this from the outer scope, creating a reference loop and preventing the object from being garbage-collected at all:
registerDisposer(this, Closeable {
this.res1.close()
this.res2.close()
})
Is there an annotation I can add to the disposer parameter that will trigger a warning in this situation?
As of this writing, the answer seems to be: probably not.
It turns out a registerDisposer function already exists as the register method of java.lang.ref.Cleaner, and it has no such annotation.
In Android, there is a similar annotation for android.os.AsyncTask, but that simply warns at any anonymous object having AsyncTask as its base class, whether it captures this or not. (This makes sense in Java, where anonymous classes always capture this, but not in Kotlin.)
I want to write a helper function to simplify viewmodel calls to services. In the library that this project uses (and which I cannot modify) there are a few different promise types that need to be used in the same exact way in every function, the only thing that varies is the (()->Unit) lambdas passed to them.
Despite these promise types having the exact same members and being used the same way, they don't share a common interface so in order to write this helper function, it would seem to me that I would have to overload it and duplicate the function body. Is there any way to avoid doing that?
A sort-of minimal example:
private fun myHelper(promise: PromiseTypeA | PromiseTypeB | PromiseTypeC, cbSuccess: ()->Unit, cbFail: ()->Unit) {
loaderBlock();
compMan.add(promise.sub(ioScheduler).obs(uiScheduler).onSuccess(cbSuccess).onFail(cbFail))
}
In reality, I would also nest the passed lambdas and do stuff with them making this function body much longer but this should illustrate the situation. PromiseTypeA, PromiseTypeB and PromiseTypeC all have the same members, get used the same way but have no common interface or ancestor. The OR operator I used in argument definition represents what I'd like to be able to do (like in TypeScript) but I cannot. How do I do the equivalent in kotlin?
Kotlin is strict on types and doesn't do "duck typing". If the different promise types don't explicitly implement a common interface, but just happen to have the same member names, these are conceptually different members.
The code is therefore not "duplicated" (at least in the eyes of Kotlin) because the function calls are technically not the same.
There is no way that I know of to make Kotlin understand that you want to give the same semantics to these names (without changing the source code of these types to make them implement an interface). I think this is the sort of things that the "traits" feature would enable if it were added to the language.
There is no "Union types" in Kotlin, so to unify usage of this classes, you will need to:
Define a common interface
interface Promise {
fun sub(): Promise
fun obs(): Promise
fun onSuccess(): Promise
fun onFail(): Promise
}
Write some boilerplate code:
fun PromiseTypeA.toPromise() = object : Promise {
override fun sub(): Promise {
this#toPromise.sub()
return this
}
override fun obs(): Promise {
this#toPromise.obs()
return this
}
override fun onSuccess(): Promise {
this#toPromise.onSuccess()
return this
}
override fun onFail(): Promise {
this#toPromise.onFail()
return this
}
}
//and so on for other types of promises
After that everything is easy: define your helper function for Promise parameter type
private fun myHelper(promise: Promise, cbSuccess: ()->Unit, cbFail: ()->Unit) {
//...
}
and call it with:
myHelper(promiseA.toPromise(), {/*...*/}, {/*...*/})
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.
Kotlin allows to name a function same as an existing class, e.g. HashSet with initializer function could be implemented like this:
fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) {
add(fn(it))
}
}
When used, it looks like a normal HashSet constructor:
var real = HashSet<String>()
var fake = HashSet(5) { "Element $it" }
Should this be avoided or encouraged and why?
UPD
In the updated coding conventions, there's a section on this topic:
Factory functions
If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.
Example:
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}
The motivation I described below, though, seems to still hold.
As said in documentation about the naming style:
If in doubt default to the Java Coding Conventions such as:
methods and properties start with lower case
One strong reason to avoid naming a function same to a class is that it might confuse a developer who will use it later, because, contrary to their expectations:
the function won't be available for super constructor call (if the class is open)
it won't be visible as a constructor through reflection
it won't be usable as a constructor in Java code (new HashSet(n, it -> "Element " + it) is an error)
if you want to change the implementation later and return some subclass instance instead, it will get even more confusing that HashSet(n) { "Element $it" } will construct not a HashSet but, for example, a LinkedHashSet
It's better to show it explicitly that it's a factory function, not a constructor, to avoid this confusion.
Naming a function same to a class is generally avoided in stdlib, too. Given SomeClass, in stdlib a preferred naming style for factory functions is someClassOf, someClassBy or whatever explains the semantics of the function best. The examples:
generateSequence { ... } and sequenceOf(...)
lazy { ... } and lazyOf(...)
compareBy { ... }
listOf(...), setOf(...), mapOf(...)
So, one should definitely have strong reason to have a function mimic a constructor.
Instead, a function's name might tell a user more (even everything) about its usage.
I agree with +hotkey. It's probably best to avoid confusion in this case.
If it's only used internally and all the other devs (if any) are okay with it, though, I'd say to go for it. Python acknowledges that idea and I love it. Heck, they go both ways, being okay with you naming a class in function case, too, if it feels more like it's acting like a function. But, Python doesn't have to deal with Java interop, so definitely don't do it for public code.