Check if generic is an array with inline function - arrays

How can I check if a Generic is an Array using an inline function?
I tried with the following code:
class Mediator {
inline fun <reified C> mediate(string: String): Container<C> {
if (C::class == Int::class) {
//It works
}
else if (C::class == Array::class) {
//It doesn't work!
}
throw IllegalStateException("Yopta")
}
}
But it doesn't work. Maybe because it can be Array<Whatever>?
How can I do it?

Contrary to collections where for example List<String> and List<Int> are internally represented by the same class List, in arrays the type parameter is a part of the type itself. That means Array<String> and Array<Int> are internally represented as different types and as far as I know, they don't have a common super type.
I don't know a pure Kotlin solution to check if a class is an array. It seems to me like an overlook in the design of the reflection API. If you don't mind using the Java reflection, you can do it like this:
else if (C::class.java.isArray) {
Update
There is one interesting fact here. In the Kotlin type system we could consider Array<out Any?> to be a supertype of all arrays. For example, we can upcast to it without an explicit cast operator:
val intArray = arrayOf(1, 2, 3)
val arr: Array<out Any?> = intArray
However, for the reflection API these two types are entirely different:
// false
println(Array<Int>::class.isSubclassOf(Array<out Any?>::class))
I assume this is due to how arrays where implemented in Java. I'm not even sure if it would be technically possible to return true in the code above. Still, it is concerning it provides a different result than the type system at a compile time and it doesn't even produce a warning.

Actual answer that solves the issue here.
Since broot added an actual answer I'll just leave this here as a note as to how we can see that he is right basically.
If we make the call like this:
Mediator().mediate<Array<Int>>("")
Adding a simple check inside the function like this makes it a bit confusing as to why they are not equal.
println(C::class) //class Kotlin.Array
println(Array:class) //class Kotlin.Array
But doing the same for the underlying java class shows that they are not really the same object.
println(C::class.java) //class [Ljava.lang.Integer
println(Array:class.java) //class [Ljava.lang.Object
So changing the statement to:
if(C::class.java == Array<Int>::class.java)
Will make the example work ... for Int only. All other "infinite" possibilities will have to be added manually. Not an issue if you just want to check Array<X> only, but definitely not generic.

Related

Why does generic TArray Create syntax differs from other class functions?

I've noticed something that appears to me as an inconsistency in the generic TArray syntax (and drives me crazy...)
The "constructor" function requires to be called by specifying the type before the function name.
MyArray := TArray<Integer>.Create(3, 2, 1);
The other class functions requires to be called by specifying the type after the function name
TArray.Sort<Integer>(MyArray);
Is there a pratical reason why they did that?
The generic array is defined like this
TArray<T> = array of T;
This an alias for a dynamic array. Dynamic arrays have an intrinsic Create method. Even non-generic ones.
type
TMyDynArr = array of Integer;
....
arr := TMyDynArr.Create(0, 1, 2);
This Create method is a compiler intrinsic. Notice how it accepts arbitrary numbers of arguments.
On the other hand there is the class TArray, with its generic Sort method. This is implemented in the RTL. Remember that TArray is never instantiated, it's just a home for generic class methods.
My guess is that adding methods to the dynamic array type requires compiler support because they are intrinsic functions. But adding to TArray is simpler because it is done at the RTL layer, not requiring compiler support.
There's nothing you can do to change anything here, so there is little to be gained by fretting about this. You can't change it. Just get used to it.
The first TArray is a system type definition of array of T. The creation could be written this way as well:
MyArray := [3,2,1];
The second TArray is a class defined in Generics.Collections.
They have nothing to do with each other.
Note also that the TArray class way of using generics is called Parameterized Methods.
Type
TArray = class
...
class procedure Sort<T>(var Values: array of T); overload; static;
...
end;
That is a way to reduce code duplication.

Kotlin array types and class literals

I am trying to deserialize an array of JSON objects with GSON. So the simple call:
val arrayOfFoo = gson.fromJson(source, Array<Foo<*>>::class.java>)
should do the trick. But type erasure tells us, that Foo<*> does not exist at runtime, so the error "Only class literals are allowed on the left hand side of a class literal" pops up. Well, so the solution must be:
val arrayOfFoo = gson.fromJson<Array<Foo<*>>>(source, Array::class.java)
Unfortunatelly, now the Kotlin compiler magic - that turns arrays of Wrapper types into primitive arrays - can not be sure what to do and tells us:
"Array class literals require a class type. Please specify one in angle brackets".
But, wait: This is, what did not work a second ago. Using
Array<Foo>::class.java
does not work, too, since now the compiler tells us: "One type argument is expected for Foo".
I personally can not see a way to solve that. Is it impossible to give a class literal of a typed array, which's type also expects a type parameter?
You can get the array class from an array instance, for example either one of
arrayOf<Foo<*>>()::class.java
java.lang.reflect.Array.newInstance(Foo::class.java, 0)::class.java
The basic problem: You need to specify the type of your array. This is done using a TypeToken in Gson.
I hope this helps:
val listType = object : TypeToken<Array<String>>() {}.type
val json = """["1"]"""
val yourClassList :Array<String> = Gson().fromJson(json, listType)
print(yourClassList)
Note that for primitives, it is simpler: Gson().fromJson(json, IntArray::class.java)

C++ arrays and System::Single?

I'm relatively new to C++, and I'm trying to take an array within a class, and set it equal to a passed in array.
public ref class Example {
array<float> ^ myarray1 = gcnew array<float>(3);
public:
Example(float^ myarray2) {
int i = 0;
while (i<3) {
myarray[i] = myarray2[i];
i += 1;
}
}
In the main function, the constructor is called as follows:
float myarray2[] = {1,2,3};
Example ^example1 = gcnew Example(*myarray2)
The errors I get is are as follows:
System::Single' has no default indexed property (class indexer)
expression must have pointer-to-object or handle-to-C++/CLI-array
type
Both of these errors are identified as happening where I am saying myarray[i] = myarray2[i].
I would greatly appreciate any help with solving this problem. I can't see where or how System::Single is getting pulled in as an error message. And, before it is suggested, I know I can get to work with setting myarray2 as a array float like myarray1, but I want it to work passing in myarray2 as float^ myarray2.
Since you say you're new to C++, let me point out that you're not writing classic C++ there. You're writing C++/CLI, which is a set of language extensions to C++ designed to interoperate with the CLI (.NET Framework). Because of this, the type float in your code is an alias for the type System::Single of the framework.
Regarding the indexer issue, the error messages pretty much spell out the cases in which you would be allowed to use an indexer:
System::Single' has no default indexed property (class indexer)
You could use an indexer if the type had a defined indexed property. System::Single, also known as float, doesn't happen to have one.
expression must have pointer-to-object type
You could use the indexer if the type was a non-void pointer type. You'd have to declare it like this:
Example(float* myarray2) {
In this case, myarray2[i] is equivalent to the expression *(myarray2 + i).
or handle-to-C++/CLI-array type
You could use the indexer if the type was a handle (^) to a C++/CLI array type. As you already know, you'd have to declare it like this:
Example(array<float> ^ myarray2) {
The bottom line is that, although you can treat a float* (pointer to float) like a C-style array of float (as a result of the rules of C and C++ about arrays and pointer arithmetic), these things simply do not apply to the float^ (handle to float) type (which is C++/CLI-specific).
Example(float^ myarray2)
That does not mean what you think it does. You are used to C language behavior, a float[] can automatically decay to a float* to the first element of the array. Somewhat unfortunately also carried forward into C++.
But not into C++/CLI, it is fundamentally unverifiable code. And responsible for a very large number of bugs and security problems. One core problem is that your constructor has no idea how many elements are stored in the array. You hard-coded "3" but if the caller passes an array that's smaller then Very Bad Things happen.
What it actually means is "reference to a boxed copy of a System::Single". The compiler tries to make sense of that, inevitably it starts to get very confused what you try to do next. Like using the [] operator, that requires the type to have an indexer. A float doesn't have one.
You need either:
Example(array<float>^ myarray2)
Which is safe and verifiable, you can't index the array out of bounds. And you don't have to hard-code "3" anymore, you can simply use myarray2->Length instead. And you don't (usually) have the copy the array anymore, simply assign myarray1. You'd call the constructor by passing gcnew array<float> { 1, 2, 3 }.
Or:
Example(float* myarray2)
Which works just like the way it does in C and C++. And required if you want to call the constructor with that float[]. Not verifiable, you need that magic "3". Do consider adding an extra argument to pass the array length.

is it possible to write a method to sort an array of objects with respect to a specific field?

i mean is it possible to have a method that gets as its parameters an array of objects and another parameter which indicates which field of the objects we are using to sort the array ?
for example if the objects are contacts if we call sort(contacts , name) it would sort them with respect to name. if we call sort(contacts , number) it sorts them according to their numbers.
maybe by sending an String of the field we want !! something like :
class sorting {
public static bubble_sort(Object[] array , String field){
for(int i =0; i<array.length ; i++){
if(array[i].field > array[i+1].field)
swap(array ,i ,i+1);
}
}
(preferably in java) (and please include examples of the solutions you give !)
Assuming this is Java: yes, it is possible. You can use reflection to get the field type and value and then compare them. It would not be a good idea. Much better to use Comparator with the existing sort method.
A method that would work in pretty much any language is to pass in some kind of function object.
class sorting {
public static bubble_sort(Object[] array, FunctionObject ordering) {
for(int i =0; i<array.length ; i++){
if(ordering(array[i+1], array[i]))
swap(array ,i ,i+1);
}
};
different languages are going to have different syntaxes for such a function object -- what its type is, etc -- but pretty much every language is going to have some way to do it.
Generally the best signature for it is one that takes two different objects, and returns true if the left one is less than the right one.
Similarly, different languages are going to have different ways of invoking a function object. Some may require ordering.Invoke( array[i+1], array[i] ).
In that function object, compare the field in question. If the language/objects have reflection, you can sometimes do this via field name directly.
As this pattern is very useful, languages tend to make it easier as they mature. So the most recent version of your language may have a syntax to create such objects with far less syntax, and invoke them with less syntax as well.

Scala arrays and parameterized types

I'm trying to define a generic class that takes a parameterized type T and then use the type in an Array definition in the class. I wrote the following which I thought seemed like it should work
class MyClass[T] {
val myarr:Array[T] = new Array[T](10)
}
But the compiler complains with the following
can't find the class manifest for element type T
value newArray is not a member of Null
Anyone know whats going on here and what its not happy about?
The compiler needs to know how to instantiate things of type T. In the traditional Java way of handling generics through type erasure, this cannot reasonably be done; the compiler just says, "Hey, I don't know what T is, so I don't feel so great about allowing you to instantiate a T like that." In Scala, however, there is a word-around for this: manifests. In order to include the manifest for T, just change the first line of that code to
class MyClass[T : Manifest] {
That's it.

Resources