I'm trying to create an AnimalFactory that returns generic factories for making different types of Animals, depending on the arguments passed to the AnimalFactory.
Here's the code:
interface Animal {
fun talk(): String
}
class Cow: Animal {
override fun talk(): String {
return "mooo"
}
}
class Cat: Animal {
override fun talk(): String {
return "miow"
}
}
class Dog: Animal {
override fun talk(): String {
return "bark"
}
}
object AnimalFactory {
fun <T: Animal> AnimalMakerFactory(type: String): AnimalMaker<T> {
val maker = when (type) {
"cat" -> CatMaker()
"dog" -> DogMaker()
else -> CowMaker()
}
return maker
}
}
interface AnimalMaker<out T: Animal> {
fun make(): T
}
class CatMaker: AnimalMaker<Cat> {
override fun make(): Cat {
return Cat()
}
}
class DogMaker: AnimalMaker<Dog> {
override fun make(): Dog {
return Dog()
}
}
class CowMaker: AnimalMaker<Cow> {
override fun make(): Cow {
return Cow()
}
}
I get a type exception:
Type mismatch.
Required: AnimalMaker<T>
Found: AnimalMaker<Animal>
I thought that AnimalMaker would solve this, but apparently not. Why is AnimalMaker<T> not of type AnimalMaker<Animal> here?
The return value of the function is AnimalMaker<T> and not AnimalMaker<Animal> because that’s what you declared as the return type. The variable maker is indeed an AnimalMaker<Animal> but that isn’t a match for what the function is supposed to return because T could be a subtype of Animal.
You declared your function as having a generic type of T: Animal. Generic types are always an input to the function. In this case, it doesn’t make sense to use a generic input to the function because there’s no way to enforce that the type given is a match for the input String it corresponds with. To make your function work, you can remove <T : Animal and declare that it returns AnimalMaker<Animal>.
A little more explanation. There are two reasons why you might want to use generics in a function signature.
Enforce input parameter types.
Determine the output type.
You might use generics for one or both reasons (but the second can only be done by itself in a useful way by using reified generics, except in very specific cases where the returned class won’t be producing anything).
In your case, your input generic is not used to enforce the input parameter since that is just a String. To use it for the second reason, you would have to cast your return value’s type to the unknown (to the compiler) type T which would be unsafe because there’s no way to know if the input type given at the call site is a valid match for the given input String. And if you expected the call site to pass the right type, it would be redundant and error prone to also require a matching String to be passed.
Edit:
If you know the input type at compile time, then you can do this with reified generics. Get rid of the String input. It would look like this:
object AnimalFactory {
inline fun <reified T: Animal> AnimalMakerFactory(): AnimalMaker<T> {
#Suppress("UNCHECKED_CAST")
return when (T::class) {
Cat::class -> CatMaker()
Dog::class -> DogMaker()
Cow::class -> CowMaker()
else -> error("No factory found for type ${T::class}.")
} as AnimalMaker<T>
}
}
// Example usage
val someCatFactory = AnimalFactory.AnimalFactoryMaker<Cat>()
val cat: Cat = someCatFactory.make()
Inside this function, it is up to you to match the types up correctly, or there will be a ClassCastException at runtime. It seems logically it should be able to automatically cast them, but the compiler isn't sophisticated enough (yet?).
Related
If I have the following code:
fun main() {
println(Example("test", 1))
}
class Example(private val text: String, private val num: Int) {
override fun toString(): String {
return "String: $text $num"
}
}
and it works.
Is there any way to do this for types different from string?
Example:
class Example {
fun toList(): List {
//Convert to list...
}
}
thisFunctionRequireList(Example2())
I will first explain how
println(Example1())
works, and from there, create something similar.
First, note that println has many overloads. This println call does not call the println(String) overload. It calls the println(Any?) overload.
The println(Any?) overload is implemented to transform the Any parameter into a String using toString, and then calls the println(String) overload using that string. Here is the Kotlin/Native implementation:
public actual fun println(message: Any?) {
println(message.toString())
}
Note that it is able to do this, only because Any?, and by extension Any, declares the toString method. This allows it to convert any value you pass, to a String. At runtime, this gets dispatched to the toString override that you declared in Example1.
Therefore, it is not because you overrode toString, that you were able to call println with Example. It is because
println has an overload that takes Any, allowing you to pass anything into it
Any also declares a toString that you can override, which println(Any) also uses in its implementation
Any does not declare a toList method, so we can't use Any if we want to do the same for List.
We can declare a new interface for types that can be converted to lists:
interface ConvertibleToList<T> {
fun toList(): List<T>
}
This is like an Any, but only for types that implement it. Example2 can then implement the interface:
class Example2: ConvertibleToList<String> {
override fun toList(): List<String> {
//Convert to list...
}
}
Now suppose there is an existing function that takes a List<String>:
fun doThingsToStrings(strings: List<String>) { ... }
You can add a new overload of this, with the parameter type being ConvertibleToList<T>:
fun doThingsToStrings(strings: ConvertibleToList<String>) = doThingsToStrings(strings.toList())
doThingsToStrings becomes just like println, with one overload taking the "exact" type (List<String>), and another overload taking types that can be converted to the "exact" type (ConvertibleToList<String>).
Now you can call doThingsToStrings with Example2()!
this custom function call's a lambda block when null.
I expected the function definition below to enforce the same return type. : T
Is their a way to enforce that be block returns type T ?
inline fun <T> T?.whenNull(block: () -> T): T {
if (this == null) {
return block() //accepts any return type
} else {
return this
}
}
fun main() {
val x : Int? = null
println(x ?: 42)
println(x.whenNull { 42 })
println(x.whenNull { "why is kotlin not enforcing return of the same type?" })
}
T in the second whenAll call is being inferred as Any. Imagine that all occurrences of T are replaced Any, the call would be valid, wouldn't you agree? Int and String are both subtypes of Any, after all.
inline fun Any?.whenNull(block: () -> Any): Any {
if (this == null) {
return block()
} else {
return this
}
}
fun main() {
println(x.whenNull { "why is kotlin not enforcing return of the same type?" })
}
Basically, the Kotlin compiler is "trying too hard" here to make your code compile, and infers an unexpected type for your type parameter.
There exists an internal annotation #kotlin.internal.InputTypesOnly that would prevent your code from compiling if the type inferred is not mentioned in one of the input types (parameter types, receiver type, etc) of the function.
In this case, the input type is just Int?, and T is inferred to be Any, so it would be make your code not compile as expected. Unfortunately though, this annotation is internal, and you cannot use it :( KT-13198 is the ticket about making it public.
Interestingly, when passing this to the block the type is preserved and works as expected.
inline fun <T> T?.whenNullAlt(block: (T?) -> T): T {
if (this == null) {
return block(this) // "this" is superfluous, but enforces same return type
} else {
return this
}
}
fun main() {
val x : Int? = null
println(x.whenNullAlt { 42 })
println(x.whenNullAlt { "does not compile" })
}
As other answers pointed out, this is technically correct from Kotlin viewpoint because it can infer T to Any and it would compile.
However, while technically correct, this is a known problem in Kotlin language and is going to be fixed some day. That noted, let's try to understand why your answers's code works while your questions' doesn't.
The reason for this is that lambdas are always inferred last: imagine it as being a queue on what parts of the expression need to have their types inferred and anything inside a lambda is always at the end of the queue, no matter where the lambda is in the expression. So, when going over your example, it infers everything else, decides that the type of this should be Int?, than goes to the lambda, sees a String return type and merges them into Any being very proud of itself.
In the other example, however, the lambda is passed an external fact about it's parameter — the already inferred Int from the receiver (lambda is always the last to get the info, remember?). That way the inference inside the lambda fails because the argument and the result type are in disagreement.
If I have a following interface:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
Would it be possible have implementation of this interface that does not take Params?
To have effectively something like:
interface BaseDataRemote<T> {
fun getData(): Single<T>
}
Implementation is as follows:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
I use Dagger 2 to module to bind this implementation:
#Module
internal interface RemoteModule {
#Binds
#CoreScope
fun bindsSellerRemote(remoteSellerDataSource: RemoteSellerDataSource): BaseDataRemote<SellerEntity, Nothing>
}
I tried using Nothing as second type parameter, but it does not seem to work
(I'm getting required: class or interface without bounds error
Full error message:
RemoteSellerDataSource.java:6: error: unexpected type
public final class RemoteSellerDataSource implements com.bigchangedev.stamps.business.sdk.data.base.data.BaseDataRemote<SellerEntity, ?> {
^
required: class or interface without bounds
found:?
Thanks.
EDIT: the original answer was a pure Kotlin answer because the OP didn't mention Dagger.
Using Nothing is correct and works in pure Kotlin. However, Dagger seems to convert your code to Java, and in doing so it uses wildcards for the generics (which it doesn't like because it wants exact type matches). To avoid this issue, you can try using #JvmSuppressWildcards on your generic type parameters:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, #JvmSuppressWildcards Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
Although I'm not sure what will happen in Java with Nothing in that case. I guess this should have the same effect on the Java code as removing the in variance for the second type param in the interface declaration, but without weakening your Kotlin types.
Another workaround would be to use Unit instead of Nothing, which Dagger will most likely convert to Void in this case. This is not great for your types, though.
Original answer:
You can technically already call getData() without arguments thanks to the default value. An implementation that doesn't care about the params argument can simply expect null all the time.
The Kotlin type that only contains null and no other value is technically Nothing?, and since getData is defined with Params? (note the ?) as input, it should be correct to specify Nothing (even without ?) as second type argument. So you should be able to define an implementation like this:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> {
// params will always be null here
}
}
To avoid confusion for the users, this implementation may additionally provide a getData() method without arguments at all:
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> = getData()
fun getData(): Single<T> {
TODO("implementation")
}
}
Simply, I want a function like:
fun <T> convert(val foo: String, fooT: KType) : T {
...?
}
For Int, it would return foo.toInt(), for Double, foo.toDouble(), and to some unknown type, just throw an exception. I think it's not so hard to create my own switch statement for the types I expect, but out of curiosity - is there a way already?
Recommended way
Unfortunately, there's no easy generic way because we're not dealing with casts, but method calls. This would be my approach:
fun <T> convert(str: String, type: KType) : T {
val result: Any = when (type.jvmErasure)
{
Long::class -> str.toLong()
Int::class -> str.toInt()
Short::class -> str.toShort()
Byte::class -> str.toByte()
...
else -> throw IllegalArgumentException("'$str' cannot be converted to $type")
}
return result as T // unchecked cast, but we know better than compiler
}
Usage:
#UseExperimental(ExperimentalStdlibApi::class)
fun main() {
val int = convert<Int>("32", typeOf<Int>())
println("converted: $int")
}
Instead of a KType parameter, you could also use a Class<T> and make the function reified, so it can be called as convert<Int>("32") or even "32".toGeneric<Int>().
Hardcore way
While there is no easy way, it is possible to access the type using heavy reflection and relying on implementation details. For this, we can extract the type name from the KType object, find an extension method (in a different class) that matches, and call it using reflection.
We have to use to*OrNull() instead of to*(), because the latter is inline and won't be found by reflection. Also, we need to resort to Java reflection -- at this time, Kotlin reflection throws UnsupportedOperationException for the types involved.
I do not recommend this in productive code, as it's inefficient and can break with future standard library versions, but it's a nice experiment:
fun convert(str: String, type: KType): Any {
val conversionClass = Class.forName("kotlin.text.StringsKt")
// here, the to*OrNull() methods are stored
// we effectively look for static method StringsKt.to*OrNull(String)
val typeName = type.jvmErasure.simpleName
val funcName = "to${typeName}OrNull" // those are not inline
val func = try {
conversionClass.getMethod(funcName, String::class.java) // Java lookup
} catch (e: NoSuchMethodException) {
throw IllegalArgumentException("Type $type is not a valid string conversion target")
}
func.isAccessible = true // make sure we can call it
return func.invoke(null, str) // call it (null -> static method)
?: throw IllegalArgumentException("'$str' cannot be parsed to type $type")
}
Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()