why the translated kotlin code complains about a Array<BaseData>? to be a Array<out BaseData> - kotlin

Having a java class, using androidStudio to translate to kotlin.
Got a error and not sure how to correctly translate it.
The java code:
public class BaseDataImpl extends BaseData {
private final BaseData[] translators;
public BaseDataImpl(final BaseData... translators) {
this.translators = cloneArray(translators);
}
public static <T> T[] cloneArray(final T[] array) {
if (array == null) {
return null;
}
return array.clone();
}
}
after the code translation, got error: required Array<BaseData>?, found Array<out BaseData>, but the translators in the cloneArray<BaseData>(translators) call is defined as val translators: Array<BaseData>?,
anyone could help to explain?
class BaseDataImpl(vararg translators: BaseData) : BaseData() {
private val translators: Array<BaseData>?
init {
this.translators = cloneArray<BaseData>(translators) //<=== error: required Array<BaseData>?, found Array<out BaseData>
}
companion object {
fun <T> cloneArray(array: Array<T>?): Array<T>? {
return array?.clone()
}
}
}

It is written in the Kotlin function reference regarding varargs:
Inside a function a vararg-parameter of type T is visible as an array of T, i.e. the ts variable in the example above has type Array<out T>.
where the referenced function was:
function <T> asList(vararg ts: T): List<T>
So in your case you actually pass an Array<out BaseData> but you only accept an array of type Array<T>? (in your case Array<BaseData>). Either you adapt all of the types to Array<out T> (which basically is similar as saying List<? extends BaseData> in Java) or you take care that you are only dealing with Ts instead, e.g. with:
inline fun <reified T> cloneArray(array: Array<out T>?): Array<T>? {
return array?.clone()?.map { it }?.toTypedArray()
}
But look up the documentation regarding this: Kotlin generics reference - type projections. You probably can accomplish this even easier.

Related

Can I omit type in generics? - Kotlin

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")
}
}

How does Kotlin choose the generic overloaded function to call?

I'm trying to write serialization functions to be able to serialize any vector (=ArrayList) in Kotlin, as well as primitive types and classes extending a Serialize class having a toBinary() function.
I also have a custom WriteDataStream class (code below) to serialize fields with the right format, endianness, etc.
I'm new to Kotlin but have experience in C++. In C++, I used templates and template specialization to solve that problem easily, but with Kotlin I've been struggling for a few days, without success.
I have a custom vector class MyVector which extends ArrayList and adds a maximum size. I want to serialize it with any generic type T, including inner vectors like a MyVector<MyVector<MyClass>>.
My WriteDataStream contains the following:
inline fun <reified T> write(vector: MyVector<T>) {
this.writeSize(vector.size.toULong(), vector.MAX_SIZE)
for (element in vector) {
write<T>(element)
}
}
inline fun <reified T: Serialize> write(value: T) {
writeSerialize(value as Serialize)
}
inline fun <reified T> write(value: T) {
when (T::class) {
UByte::class -> {
writeUInt8(value as UByte)
}
UShort::class -> {
writeUInt16(value as UShort)
}
UInt::class -> {
writeUInt32(value as UInt)
}
ULong::class -> {
writeUInt64(value as ULong)
}
Byte::class -> {
writeInt8(value as Byte)
}
Short::class -> {
writeInt16(value as Short)
}
Int::class -> {
writeInt32(value as Int)
}
Long::class -> {
writeInt64(value as Long)
}
Boolean::class -> {
writeBoolean(value as Boolean)
}
Float::class -> {
writeFloat(value as Float)
}
Double::class -> {
writeDouble(value as Double)
}
else -> {
error("Default serialization:" + T::class.qualifiedName)
}
}
}
All the underlying functions writeXXX() are tested and work fine. However, when tying to serialize a MyVector with a class extending Serialize, I fall in the "Default serialization" case:
#Test
fun writeVectorOfStructure() {
class TestStructure: Serialize() {
override fun toBinary(stream: WriteDataStream) {
stream.writeUInt32(17U)
stream.writeUInt8(3U)
stream.writeDouble(555.555)
}
}
val value = MyVector<TestStructure>(MAX_SIZE, arrayListOf(TestStructure(), TestStructure()))
writeStream.write(value)
val bytes: UByteArray = writeStream.byteArray()
Assert.assertEquals(bytes.size, 28) // = 2 (for size) + 2*(4+1+8) = 28 bytes
}
So my question is: Why does Kotlin not use the function
inline fun <reified T: Serialize> write(value: T)
when it serializes an element of the vector (write<T>(element)) with generic T = Serialize, but instead uses the more generic one?
inline fun <reified T> write(value: T)
In C++, the compiler always uses the most fitted function.
Is there a way to overcome this limitation in Kotlin?
I have tried with and without reified types, I have tried a non-generic function as well: inline fun write(value: Serialize), but without success. The only thing that seems to work was to add a case for classes "instance of" Serialize in the fully-generic inline fun <reified T> write(value: T), but this is not really a nice solution.
Thanks you !
JVM and its bad implementation of generics
You are a victim of Java's implementation of generics, more specifically the erasure. C++ uses what is called type expansion to implement generics, meaning if you declare MyType<A> and MyType<B>, at runtime you will have two different types, language runtime will create them for you.
On the other hand what Java does is called the erasure implementation. so in java world when you say List<String> and List<Integer>, at runtime they are both identical types, that is system doesn't have any information to make a distinction between both of these, they are List type (Note that there is no type parameter, it got removed during the compilation).
Lets decompile your code and see for yourself
I wrote following code in kotlin, it matches yours
class SomeType {
inline fun <reified T: String> write(value: T) {}
inline fun <reified T> write(value: T) {}
inline fun <reified T: Any> write(vector: List<T>) {
for (element in vector) {
write(element)
}
}
}
And when I decompile the code it gives me following. (Only relevant code included)
public final class SomeType {
public final void write(#NotNull String value) {}
public final void write(Object value) {}
public final void write(#NotNull List vector) {
boolean var6;
for(Iterator var4 = vector.iterator(); var4.hasNext(); var6 = false) {
Object element = var4.next();
}
}
}
Look at the write(vector: List<T>) method's decompilation. parameter type got changed to List which is a Raw Type and its components are objects.
And for an Object best method match is public final void write(Object value) and not the one with String or in your case Serialize.

Pass a Java class reference as a function parameter in Kotlin

I want to pass a reference to a class to a function:
getCallData(ServiceCallBase::class.java)
fun getCallData(msg: Message, t: KClass<Any>): String {
return gson.fromJson((msg.obj as Bundle).getString(SERVICE_BUNDLE_KEY_DATA_TO_SERVICE), t)
}
The t parameter is not correct here. How do I correctly define the t parameter? The closest I can get is:
private inline fun <reified T> getCallData(msg: Message): String {
return gson.fromJson((msg.obj as Bundle).getString(SERVICE_BUNDLE_KEY_DATA_TO_SERVICE), T)
}
But here T is not an expression.
try this
inline fun <reified T> getCallData(msg: Message): String {
return gson.fromJson((msg.obj as Bundle)
.getString(SERVICE_BUNDLE_KEY_DATA_TO_SERVICE), T::class.java)
}
and use it like this :
getCallData<ServiceCallBase>(Message())
The problem is that ServiceCallBase is not a subtype of Any. You should change the signature to:
fun getCallData(t: KClass<*>) { ... }
Then, to call this function just use:
getCallData(ServiceCallBase::class)
But, to do that in more kotlin way use the second snipped you pasted:
inline fun <reified T> getCallData() { /* use T::class property here */ }
and call the function like this:
getCallData<ServiceCallBase>()

Kotlin - not able to find kotin equivalent of java.util.function.Function<T, R>

I am trying to convert one of the java function which takes java.util.function.Function<T, R> to Kotlin using IDEA 2019.3 Kotlin multiplatform library.
But t I could not find a way to do an equivalent function in kotlin. I can see here that there is Function1 to do a java interoperability but I am not able to do any import from import kotlin.jvm.functions.*
I am trying Kotlin for the first time. Could someone please tell what am I doing wrong.
Update- Please see my java code
import java.util.function.Function;
public class A {
Function<String, String> function;
public A(Function<String, String> function) {
super();
this.function = function;
}
public String convert(String input) {
return function.apply(input);
}
}
Not clear about your question, but assuming you are trying to duplicate functionality from Java:
In Kotlin, you do not use Function interfaces directly because functions are first-class. The Function1, Function2, etc. classes are only used to make functions available to Java code and the JVM.
If you want to create the equivalent of a Java Function<T, R>, you would define a function using either Kotlin's fun or lambda syntax.
fun getStringLength(x: String): Int {
return x.length
}
//...
val functionReference = ::getStringLength
// Java code will treat this as a Function1<String, Int>
or
val function = fun (x: String): Int {
return x.length
}
// Java code will treat this as a Function1<String, Int>
or
val functionReference = { x: String -> x.length }
// Java code will treat this as a Function1<String, Int>
To declare that a function takes a function as a parameter, you use (input) -> output syntax as the variable type:
fun <T, R> doSomething(functionalReference: (T) -> R) {
//
}
You can call a function using its referenced name:
fun <T, R> doSomething(input: T, functionalReference: (T) -> R): R {
return functionalReference(input)
}
Sounds like you want to convert a Java function that accepts a Function to an equivalent Kotlin function.
Example:
Java
public class JavaFunctions {
public static <T,R> void runAFunction(Function<T, R> userFunction){
userFunction.apply(null);
}
}
Kotlin (These two functions are equivalent)
class KotlinFunctions{
companion object{
#JvmStatic
fun <T,R> runAFunction(userFunction:(T?) -> R?){
userFunction.invoke(null);
}
#JvmStatic
fun <T,R> runAFunction2(userFunction: Function1<T?, R?> ){
userFunction.invoke(null);
}
}
}

How do I call a method in Kotlin with a different upper bound?

e.g. Given a Class<T> how do I call/invoke a method/constructor that requires Class<T> where T : Enum<T>?
fun <T : Any> handleAny(classOfT: Class<T>) {
if (classOfT.isEnum) {
handleEnum(classOfT)
}
}
fun <T : Enum<T>> handleEnum(classOfT: Class<T>) { /*...*/ }
Error: inferred type T is not a subtype of kotlin.Enum<T>
In Java I can do an unchecked call but I cannot seem to find a way to do anything similar in Kotlin.
As for now I found this quite hacky workaround for it:
private enum class DummyEnum
fun <T> handleAny(classOfT: Class<T>) {
if (classOfT.isEnum) {
handleEnum(classOfT as Class<DummyEnum>) //absolutely any enum goes
}
}
fun <T : Enum<T>> handleEnum(classOfT: Class<T>) {
println(classOfT.toString())
}
The idea is to make an unchecked cast to the type with any generic parameter satisfying the upper bound (let it be DummyEnum), which will then be erased at runtime anyway.
The limitation is that the solution doesn't work correctly with reified generics: if handleEnum had reified type parameter, it would be substituted for statically inferred type (DummyEnum).