How can I use a Generics with inheritance in Kotlin - kotlin

I am trying to understand Generics here and am struggling. I have a simple code that looks like
interface A {
}
interface B {
}
class C : A, B {
}
fun <T: A> changeVal() : T {
return C()
}
And I get the following error Type mismatch: inferred type is C but T was expected. What am I getting wrong?

You've written a function that says "Name me a subclass of A. I'll return an instance of that subclass." This signature is a lie, since you always return C(), which is a C instance, not a T for all T subclasses of A.
Generics establish a "for all" relationship. The caller is always the one who decides what the generic instantiates to, not the callee. In your case, you simply want to return A.
fun changeVal() : A
The feature you're trying to use is called existential typing, and it's not something that's available in Kotlin. In Haskell (with appropriate compiler extensions), the signature might look something like
data AContainer where
AVal :: forall a. a -> AContainer
changeVal :: AContainer
changeVal = ...
but Kotlin does not have this feature. In fact, this is exactly what subtyping in an OOP language is meant to do: it says "I have an object that has these features, but I don't know anything concrete about it". So you don't need generics to express this pattern.

Related

Kotlin static factory method with generics

Found something similar with what I want to achieve for java - java generics and static methods also implementing factory pattern with generics in java from baeldung.
In my case, I also want to have the factory as a static method, but not sure how to achieve it in Kotlin, or maybe the whole concept is wrong.
Shortly, there are certain types of Notifiers, each should handle a certain NotificationInput type. Basically they are also some kind of builders as they build up the Notification object from the input.
Considering the setup below, I get Type mismatch. Required: Notifier<T> Found: DebugNotifier (same for the other Notifier implementations).
interface Notifier<T> {
fun issue(p: NotificationInput<T>): Notification
companion object {
fun <T> getNotifier(p: NotifierParameter): Notifier<T> = when(p.type){
"0" -> DebugNotifier()
"1" -> InfoNotifier()
"2" -> ErrorNotifier()
}
}
class DebugNotifier: Notifier<Debug>{
override fun issue(p: NotificationInput<Debug>): Notification{
return Notification(
somField = p.someDebugFieldValue
)
}
}
data class NotificationInput<T>(
val data: T
)
This is how I plan to call it: Notifier.getNotifier<Debug>(notifierParameter).issue(notificationInput)
How can this be achieved, or what would be a better configuration?
As #broot already explained, the caller has control over 2 things here: the type argument T and the NotifierParameter argument, so the API is kinda broken because the caller could do:
Notifier.getNotifier<Debug>(NotifierParameter("2"))
What would you expect to happen here?
There are too many degrees of freedom in the inputs of getNotifier(), so the compiler cannot allow you to return ErrorNotifier() when you receive "2", because someone could pass <Debug> as type argument.
You cannot compare this kind of API with Java, because Java's generics are broken and allow things that don't make sense.

Is there a way in Kotlin to ensure that a generic type that inherits a interface still is a interface or to assume that it would be?

I want to declare a function with a generic type which has to inherit from another generic type that should be an interface, and some other class.
But Kotlin complains and doesn't let me do this.
class SomeClass<T: SomeInterface> {
fun <R>someFunktion(task: R) where R : SomeOtherClass, R : T {}
}
If I just replace the generic type T in the function declaration with SomeInterface, it works.
class SomeClass<T: SomeInterface> {
fun <R>someFunktion(task: R) where R : SomeOtherClass, R : SomeInterface {}
}
So it seems the problem is that Kotlin does not know whether T is an interface or a class. If it would be a class it could not work because Kotlin does not support multi inheritance for classes.
So does someone know a solution? Thank you already in advance for every effort.
Writing your above code example results in the Kotlin compiler to complain:
Type parameter cannot have any other bounds if it's bounded by another type parameter
It says that you cannot have your variable R be bound by a second type parameter T. However, for whatever reason, the problem can just be suppressed: If you add the annotation
#Suppress("BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER")
fun <R>someFunktion(task: R) where R : SomeOtherClass, R : T {}
then Kotlin will stop complaining and everything works just fine.

How do I create a lambda expression from a Kotlin interface?

I have a simple Kotlin interface:
#FunctionalInterface
interface ServiceMethod<T> {
fun doService(): T
}
This, in spite of the name, is essentially identical to Java's Supplier functional interface. The only difference is that I can implement the Supplier, and I can't implement my own.
val supplier = Supplier<String> {
"Hello"
}
val serviceMethod = ServiceMethod<String> {
"Hello"
}
The ServiceMethod implementation gives me a compiler error saying "Interface ServiceMethod does not have constructors." Huh? Of course it doesn't! It's a functional interface.
I know that I can write it as an anonymous inner class:
val serviceMethod = object : ServiceMethod<String> {
override fun doService(): String {
return "Hello"
}
}
But this is much more verbose. In this case I could just use the Supplier interface, but that won't work for other interfaces. I shouldn't have to write an interface in Java, just to be able to a lambda in Kotlin. I'd rather use a lambda for all my Kotlin interfaces, especially since I'll be writing a lot of these. Am I missing something obvious?
Use the fun interface modifier since Kotlin 1.4
In Kotlin 1.3 and earlier, SAM (single abstract method) conversions, where you can instantiate an interface like Supplier using a lambda function, were only supported for Java interfaces.
The language designers originally thought SAM conversions wouldn't be useful for Kotlin interfaces, because a Kotlin function already has a type. For example, the type of your doService function can be written as () -> T. Instead of creating an object that implements an interface, you could simply write:
val serviceMethod: () -> String = { "Hello" }
Kotlin 1.4 adds SAM conversions for Kotlin interfaces, but it doesn't work out of the box for every interface. Instead, you have to apply the special fun modifier to a Kotlin interface to make it eligible for SAM conversion.
In your example, it would simply look like this:
fun interface ServiceMethod<T> {
fun doService(): T
}
With the modifier added, you can create an instance using a lambda exactly as you were hoping in your question.
val serviceMethod = ServiceMethod<String> { "Hello" }
You can learn more in the Kotlin documentation for functional interfaces.

Kotlin: smart cast with multiple types

I'm building a CST to AST mapper for antlr so I have tons of *Context classes that I need to map to their coresponding AST nodes.
I have ANTLR-produced classes and my mapper methods:
// Demo data:
open class Super
class Sub0: Super
class Sub1: Super
// Mappers:
fun map(a: Super) = println("Super")
fun map(a: Sub0) = println("Sub0")
fun map(a: Sub1) = println("Sub1")
Then, I'd like to use it as following:
listOf(Super(), Sub0(), Sub1()).forEach {
when (it) {
is B, is C -> { print('*'); map(it) }
else -> map(it)
}
}
I'd expect it to be smart-casted to either Sub0 or Sub1 and call the correct map, that however gives:
Super
*Super
*Super
Which indicates that it chose the right path but didn't do the auto-cast.
This approach works but gets really long as you have more and more SubX's:
when (it) {
is Sub0 -> {
print("*");
map(it)
}
is Sub1 -> {
print("*");
map(it)
}
else -> map(it)
}
I know I could use some black-magic in form of reflection and iterate over all map(X)s and then use some "clever trick" to choose the right one, but I'd rather not. ;)
The smart cast does not work because the code inside the when branch is B, is C -> map(it) is type-checked only once. It is not compiled to two different sets of instructions, for one type and the other. The compiler needs to infer a single type for it that will work in both cases.
Neither of Sub0 and Sub1 can be chosen for the type of it, because choosing one of them does not cover the other. So the compiler chooses the least common supertype of Sub0 and Sub1, which is Super. Then the call to map is resolved with statically-known type Super for it.
So indeed, splitting the branches so that only a single type is mentioned in the branch conditions is the way you can fix this.

Kotlin: prevent == with wrong types from compiling

Let's consider the following simplified example:
interface I { /* some stuff */ }
object A: I { /* some stuff */ }
object B: I { /* some more stuff */ }
class Cell<J: I>(val n: Int, val j: J) {
/* some more stuff that uses j */
fun eq(c: Cell<J>): Boolean {
return n == c.n
}
}
Now Cell(1, A).eq(Cell(2, A)) compiles, but Cell(1, A).eq(Cell(2, B)) doesn't, as expected.
Now I want to replace eq with ==. Sadly, the only way I see is the following:
class Cell<J: I>(val i: Int, val j: J) {
override fun equals(c: Any?): Boolean {
c as Cell<J>
return i == c.i
}
}
This has the disadvantage that Cell(1, A) == Cell(2, B) will happily compile. I can, of course, check at runtime whether j is the same, but I would like to know it before running the program. What can I do?
What you currently have is the solution. equals does not have any type safety.
With type safety, you wouldn't be able to properly compare types on different abstractions, unless you specified the higher-tiered type first:
class Sub : Super
class Super(val num: Int)
fun compare(sub: Sub, super: Super) {
val superFirst = super == sub // would compile
val subFirst = sub == super // wouldn't compile
}
So it doesn't make sense for equals to specify a strict parameter.
The equals function has an argument of Any, so you'll never receive type-safety from this. You cannot overload the operator either, as attempting to do so will throw an error.
equals sole purpose is to check for the equality at runtime (through potential type checks & state checks), so it wouldn't be the proper tool for this.
I was looking for something similar to how == works in Haskell.
Even if you don't need it to be named ==, this doesn't interoperate well with JVM subtyping, which Kotlin needs to support (and Haskell of course doesn't). It might be instructive to look at a failed attempt:
public infix fun <A> A.eq(x: A) = this == x
This requires the receiver and argument to have the same type A, so 1 eq "" shouldn't compile, right? Wrong! The compiler "helpfully" infers A to be Any, which it couldn't do in Haskell.
Another issue: can you compare values of types Interface1 and Interface2? They could be equal because both could belong to a class implementing both interfaces.
You can actually do it in Scala, because type inference works differently there, but I don't think a good solution exists for Kotlin.