I have a problem when I try to override a generics method with Boolean,Double,Integer,Float.
It works with Date. (May because is it Serializable?)
The interface:
interface AnInterface<C, T> {
fun doSomething(items: List<T>, vararg value: C): List<T>
}
An abstact implementation: (No override doSomething)
abstract class BaseClass<C, T> : AnInterface<C, T> { ... }
It's work:
class AnImplementetion<T> : BaseClass<Date, T>() {
override fun doSomething(items: List<T>, vararg value: Date): List<T> {
// It works
}
}
It doesn't work:
class AnAnotherImplementetion<T> : BaseClass<Boolean, T>() {
override fun doSomething(items: List<T>, vararg value: Boolean): List<T> {
// It doens't
}
}
The IDE always want to implement the doSomething. When I implement it with IDE it creates always the same one.
Error message:
Class 'AnAnotherImplementetion' is not abstract and does not implement abstract base class member
public abstract fun fun doSomething(items: List<T>, vararg value: Boolean): List<T> defined in BaseClass
'doSomething' overrides nothing
How can I fix it?
Thank you
UPDATE:
It works with JAVA. But Why doesn't with Kotlin?
public class AnAnotherImplementetion<T> extends BaseClass<Boolean, T> {
#NotNull
#Override
public List<T> doSomething(#NotNull List<? extends T> items, Boolean... value) {
// It works with JAVA
}
}
UPDATE 2:
It works when vararg is nullable.
interface AnInterface<C, T> {
fun doSomething(items: List<T>, vararg value: C?): List<T>
}
It looks like a bug in kotlin compiler. As I know during compiling it decides to use primitive type (int) or wrap (Integer). Java generics can't work with primitives, so compiler uses wrap for generic-type, BUT then compiler sees, that method param is never null and replaces it with primitive-type, and type-conflict appears. And here nullable saves a day.
But I'm not sure, it's just a guess.
The kotlin reference regarding basic types contains a passage which explains how it should deal with primitive types and generics in particular.
Obviously the latter is not working correctly. When generics are involved it should box the types which it either doesn't do or which the compiler complains about falsely.
You should open a bug at https://youtrack.jetbrains.com/ and link it here too. Maybe it was also a conscious design decision.
A workaround is to use the nullable type Boolean? as that will work as it is described in the reference. It will be boxed and therefore will work with generics.
Alternatively, if you are on the JVM, you can use the java.lang.Boolean instead. It's the object type of the primitive boolean and even though it is discouraged to use the Java types in Kotlin it is a possible workaround until Kotlin behaves as it should. However... testing it, Kotlin does some more magic around it so that its usage isn't that helpful neither. You would then even need to cast the java.lang.Boolean.TRUE as java.lang.Boolean. That's clearly not helpful at all. Opening a bug is the best you can do here.
Related
I have created interface to separate domain from data layer.
interface EditRepository<T> : Repository {
fun <P, R> post(postRequest: P): LiveData<ResponseData<R>>
fun <E, R> edit(editRequest: E): LiveData<ResponseData<R>>
fun <D, R> delete(deleteRequest: D): LiveData<ResponseData<R>>
}
Each function should have it's own generic types(request and response)
After i try to implement this interface methods , I replace generic types with my own types and seem they are not working as it is unable to import my type inside angle brackets of new overriden function(pointed below on screenshot). And i do not know what I am doing wrong here. Why i can't override generic interface function?
If i try manually import my type, it refuses to accept my function as overiden
You can't change type of override function-level generic. As workaround you can make class cast
override fun <P, R> post(postRequest: Response<P>): LiveData<Response<R>> = liveData(IO){
........
emit(ResponseData.SuccessResponse(...) as ResponseData<R>)
}
but you'll get lint warning Unchecked cast:
In other hand you can use type-level generic
interface EditRepository<D,E,P,R> : Repository {
fun post(postRequest: P): LiveData<ResponseData<R>>
fun edit(editRequest: E): LiveData<ResponseData<R>>
fun delete(deleteRequest: D): LiveData<ResponseData<R>>
}
and specify required types. But with Retrofit type-level generics causes IllegalArgumentException: Type parameters are unsupported
I would like to create a generic function that allows to cast context to activity type passed in parameter.
example of the idea:
private fun <T> castContext(activityType: T): T{
//example activityType = MainActivity
return context as T
}
For this to work you need to supply the type information, normally only available at compile-time (due to type erasure). In Java you would supply instance of Class or a something called type token.
1 If the type information is available at compile-time, you can use
private inline fun <reified T: Any> castContext(activity: Any?): T {
return activity as T
}
Inline function is a compile-time only construct and thus can 'embed' the type information into the bytecode in your stead (as in passing it explicitly as function parameter) - this is done by reifying the generic type parameter.
You could further narrow down the generic parameter bounds from Any to whatever you wish to specialize this function for your needs.
2 If you want to cast dynamically, to an instance of some class, unknown at compile-time, you need to do a normal cast:
val type: KClass<*> = ...
type.cast(instance)
type.safeCast(instance)
Because Kotlin's as and as? keywords are not methods (which irritates me to no end, due to often requiring extra () for cast, I'm using this pair of functions:
/** #return this as instance of the specified type (equivalent to this as T) */
inline fun <reified T: Any> Any?.asIs(): T = this as T
/** #return this as instance of the specified type (equivalent to this as? T) */
inline fun <reified T: Any> Any?.asIf(): T? = this as? T
The use of Any? as method receiver is somewhat controversial, due to handling null implicitly, instead of explicitly on call site, using ?.
How get the type of a Generic class and cast an object to it?
I want to use this function to pass an Interface class:
protected fun <T> getInteraction(): T {
return when {
context is T -> context
parentFragment is T -> parentFragment as T
else -> throw IllegalArgumentException("not implemented interaction")
}
}
and use it like:
private var interaction: ISigninInteraction? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
interaction = getInteraction<ISigninInteraction>()
}
Kotlin, Java and JVM do have types erasure when Generics are implemented. Generics are not visible at the bytecode level. It means, you cannot use type parameters, e.g. T, directly in the function code.
Kotlin adds support for reified generics, which helps here. You may declare the function like
inline fun <reified T> getIt() : T {
...
}
With the help of reified and inline it will be possible to cast to T and return it.
https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters
The second alternative is to follow a Java practice - add the Class<T> parameter to the function and use Class#cast to cast to T instead.
You may combine the reified inline function with the approach like:
inline fun <reified T> getIt() = getIt(T::class.java)
Can I write:
#IdRes
abstract fun getHeaderId(): Int
With a val instead of a fun in kotlin? It complains I need a backing field or delegate when i write:
#IdRes <-- errors
abstract val headerId: Int
Which is the most idiomatic in this case? One-liner with a fun or mess around with a backing field (I'm not used to backing fields, maybe it's change-resistance, i have never really used them so i think they are unpleasant)
Since abstract val or var is just a function without a backing field it cannot be annotated by IdRes annotation but there is a workaround. You can use it like this:
#get:IdRes
abstract val headerId: Int
EDIT:
Why does this works? We need to closer inspect IdRes annotation and its source code:
#Documented
#Retention(CLASS)
#Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
public #interface IdRes {
}
As we can see this annotation can be used on methods, parameters, fields and local variables. When we use abstract val it's neither of those since it is abstract and we cannot have abstract fields in Java. Normally equivalent of abstract val something: Int in Java is:
private int something
public int getSomething() {
return something;
}
From example, it's easy to see that the private field is what is called backing field of a property and you can't have those as abstract so that was the problem.
As mentioned in #AtulGupta comment, #theKarlo 's answer does not force the subclass to pass in an IdRes.
Therefore, an alternative to
#IdRes
abstract fun getHeaderId(): Int
and
#get:IdRes
abstract val headerId: Int
Is to pass the value into the constructor of the class itself, so that the backing field issue can be avoided and the subclass is forced to pass in an IdRes.
For example:
abstract class SomeClass(#IdRes val idRes: Int)
How to create method that takes generic object as parameter?
Like object of class Apple or Cycle. I don't want to downcast it from Any.
fun putObject(y: <T> /*and even only "T"*/) {
}
According to the documentation:
Not only classes can have type parameters. Functions can, too. Type parameters are placed before the name of the function:
fun <T> singletonList(item: T): List<T> {
// ...
}
You have to declare that T is a type parameter. You have to do it before the name of the function (like you would in Java). Rewriting your code as follows works:
fun <T> putObject(y: T) {
// ...
}