How to avoid duplicating a function body - 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(), {/*...*/}, {/*...*/})

Related

T except one class

Suppose I've a class called Devil
class Devil
and I've method called support
fun <T> support(t : T){
}
I want to restrict this function to only accept classes other than Devil (all classes in the world, but not Devil). Something like
fun <T except Devil> support(t : T){
}
How do I do this in Kotlin? Is this even possible?
This is very likely an XY problem, so please do not apply this solution without considering something else.
One way to achieve this is to declare a non-generic overload of support() with the explicit type Devil, and deprecate that function with ERROR level:
fun <T> support(t: T) {
// do your stuff
}
#Deprecated("support() cannot be used with type Devil", level = DeprecationLevel.ERROR)
fun support(devil: Devil) {
error("NOPE.")
}
Note that this would also exclude subtypes of Devil - which is not explicitly stated in your question, but might be what you want.
However, nothing prevents users from working around it by explicitly calling the generic overload by specifying a type in <...>:
support<Devil>(Devil()) // compiles fine
support<Any>(Devil()) // compiles fine
Similarly, as #gidds pointed out, this approach also doesn't prevent compilation if you pass in a variable with a static type that is not Devil even if it holds an instance of Devil (because the compiler will choose the generic overload in that case):
val hiddenDevil: Any = Devil()
support(hiddenDevil) // compiles fine

Kotlin Interface method abstraction

I'm exploring the Substitution principal and from what I've understood about the principal is that a sub type of any super type should be passable into a function/class. Using this idea in a new section of code that I'm writing, I wanted to implement a abstract interface for a Filter like so
interface Filter {
fun filter(): Boolean
}
I would then imagine that this creates the contract for all classes that inherit this interface that they must implement the function filter and return a boolean output. Now my interpretation of this is that the input doesn't need to be specified. I would like it that way as I want a filter interface that guarantee the implementation of a filter method with a guarantee of a return type boolean. Does this concept even exists in Kotlin? I would then expect to implement this interface like so
class LocationFilter {
companion object : Filter {
override fun filter(coord1: Coordinate, coord2: Coordinate): Boolean {
TODO("Some business logic here")
}
}
}
But in reality this doesn't work. I could remove remove the filter method from the interface but that just defeats the point of the whole exercise. I have tried using varargs but again that's not resolving the issue as each override must implement varargs which is just not helpful. I know this may seem redundant, but is there a possibility to have the type of abstraction that I'm asking for? Or am I missing a point of an Interface?
Let's think about it a little. The main point of abstraction is that we can use Filter no matter what is the implementation. We don't need to know implementations, we only need to know interfaces. But how could we use Filter if we don't know what data has to be provided to filter? We would need to use LocationFilter directly which also defeats the point of creating an interface.
Your problem isn't really related to Kotlin, but to OOP in general. In most languages it is solved by generics/templates/parameterized types. It means that an interface/class is parameterized by another type. You use it in Kotlin like this:
interface Filter<in T> {
fun filter(value: T): Boolean
}
object LocationFilter : Filter<Coordinate> {
override fun filter(value: Coordinate): Boolean {
TODO()
}
}
fun acquireCoordinateFilter(): Filter<Coordinate> = LocationFilter
fun main() {
val coord: Coordinate = TODO()
val filter: Filter<Coordinate> = acquireCoordinateFilter()
val result = filter.filter(coord)
}
Filter is parameterized, meaning that we can have a filter for filtering strings (type is: Filter<String>), for filtering integers (Filter<Int>) or for filtering coordinates (Filter<Coordinate>). Then we can't use e.g. Filter<String> to filter integers.
Note that the code in main() does not use LocationFilter directly, it only knows how to acquire Filter<Coordinate>, but the specific implementation is abstracted from it.
Also note there is already a very similar interface in Java stdlib. It is called Predicate.
my interpretation of this is that the input doesn't need to be specified.
Where did you get that interpretation from?
You can see that it can't be correct, by looking at how the method would be called.  You should be able to write code that works for any instance of Filter — and that can only happen if the number and type of argument(s) is specified in the interface.  To use your example:
val f: Filter = someMethodReturningAFilterInstance()
val result = f.filter(coord1, coord2)
could only work if all implementations used two Coordinate parameters. If some used one String param, and others used nothing at all, then how would you call it safely?
There are a few workarounds you could use.
If every implementation takes the same number of parameters, then you could make the interface generic, with type parameter(s), e.g.:
interface Filter<T1, T2> {
fun filter(t1: T1, t2: T2): Boolean
}
Then it's up to the implementation to specify which types are needed.  However, the calling code either needs to know the types of the particular implementation, or needs to be generic itself, or the interface needs to provide type bounds with in variance.
Or if you need a variable number of parameters, you could bundle them up into a single object and pass that.  However, you'd probably need an interface for that type, in order to handle the different numbers and types of parameters, and/or make that type a type parameter on Filter — all of which smells pretty bad.
Ultimately, I suspect you need to think about how your interface is going to be used, and in particular how its method is going to be called.  If you're only ever going to call it when the caller knows the implementation type, then there's probably no point trying to specify that method in the interface (and maybe no point having the interface at all).  Or if you'll want to handle Filter instances without knowing their concrete type, then look at how you'll want to make those calls.
The whole this is wrong!
First, OOP is a declarative concept, but in your example the type Filter is just a procedure wrapped in an object. And this is completely wrong.
Why do you need this type Filter? I assume you need to get a collection filtered, so why not create a new object that accepts an existing collection and represents it filtered.
class Filtered<T>(private val origin: Iterable<T>) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then in your code, anywhere you can pass an Iterable and you want it to be filtered, you simply wrap this original iterable (any List, Array or Collection) with the class Filtered like so
acceptCollection(Filtered(listOf(1, 2, 3, 4)))
You can also pass a second argument into the Filtered and call it, for example, predicate, which is a lambda that accepts an element of the iterable and returns Boolean.
class Filtered<T>(private val origin: Iterable<T>, private val predicate: (T) -> Boolean) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then use it like:
val oddOnly = Filtered(
listOf(1, 2, 3, 4),
{ it % 2 == 1 }
)

How do I specify an ActionListener in Kotlin?

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.

Using Fuel's responseObject with a generic call site

I've a problem using Fuel's responseObject in a generic fashion. I'm trying to develop a centralized method with components getting their HTTP response object already deserialized, ready to go. It looks like this:
class Controller(private val url: String) {
fun <T> call(endpoint: String): T {
return "$url/$endpoint".httpGet().responseObject<T>()
}
}
class App(private val controller: Controller) {
fun getModel() {
val model = controller.call<AppModel>("model")
// use model
}
}
Of course, Controller.call would handle errors, and add common request parameters. The deserialization from JSON is supposed to be handled by Jackson (AppModel is a simple data class Jackson should pick up automatically), so I'm working with fuel-jackson:1.12.0 as an added dependency.
Now, using Kotlin-1.2.21, I get this compiler error:
Error:(35, 97) Kotlin: Cannot use 'T' as reified type parameter. Use a class instead.
How do I work around this, perhaps by switching to a different Fuel method?
I've considered making call inline (to reify T), but this defeats the purpose of having a private val url.
I don't think there's a simple workaround to this problem.
First, there's no way to call a Kotlin inline function with a reified type parameter without either using a concrete type or propagating the type argument through a chain of generic calls to inline functions, so you have to call .httpGet().responseObject<T>() from an inline function and use a reified type parameter as T.
Next, there's a reason for the restrictions on what an inline function can access. Basically, allowing inline functions to access non-public API would sometimes break binary compatibility. This is described in the docs here.
What you can do is, as suggested in the docs, make private val url: String a #PublishedApi internal val and, accordingly, go on with inline fun <reified T> call(...).
If you are worried about url becoming effectively public, you might want to take a look at this Q&A suggesting a workaround with #JvmSynthetic.

Should we avoid naming a function same as an existing class in Kotlin? Why?

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.