In some sources I read that the first creates an array of elements of primitive type Int, and the second of packed Integer, in others that in Kotlin there are no primitive types, and it is the same. I haven't found any consensus, I'd be grateful if someone could explain.
Googled and read the book Kotlin in Actions
arrayOf produce an object of class Array<T>. As you initialize array using this function, primitive values that you provide as arguments are being boxed. In other words, primitive integer value 1 will be converted to the object of type Int with value 1.
val array = arrayOf(1, 2, 3) // array's type is Array<Int>
intArrayOf is a function to create object of type IntArray. This class does not have boxing overhead. Therefore values that you provide are not being boxed.
val array = intArrayOf(1, 2, 3) // array's type is IntArray
Note that both classes IntArray and Array<T> have no inheritance relation. But they contain same set of methods and properties.
IntArray represents primitive type arrays, which are designed specifically to prevent deriving array type from provided elements and avoid boxing overhead.
However, if you are calling get method on IntArray, you will get value of type Int, same as when you call get on Array<Int>.
intArrayOf() and arrayOf() are both functions in Kotlin for creating arrays. The main difference between the two functions is the type of elements that the resulting arrays can hold.
intArrayOf() is used to create an array of primitive Int values, while arrayOf() is used to create an array of objects, such as String, Float, or other object types.
Here's an example of using intArrayOf():
val intArray = intArrayOf(1, 2, 3, 4, 5)
And here's an example of using arrayOf():
val stringArray = arrayOf("A", "B", "C")
Note that while intArrayOf() creates an array of primitive Int values, arrayOf() creates an array of Int objects, which are reference types. This means that the elements in the array created by arrayOf() are objects that can have different values, while the elements in the array created by intArrayOf() are primitive values that cannot have different values.
Related
Here's my Foo data class definition
data class Foo(
var fooArg: Array<Int?>? = null,
)
And here's the call to it:
val bar: Array<Int> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
But this gives an error type mismatch: required Array<Int?>? but found Array<Int>
I am confused, it is expecting a nullable type, and I provide it with a non-null value, how is that type mismatch?
You declared bar as Array<Int>. Non-null types are not compatible with nullable types*. Change it to Array<Int?> and it will work:
val bar: Array<Int?> = arrayOf(1,2,3)
val foo = Foo(fooArg = bar)
Or alternatively:
val bar = arrayOf<Int?>(1, 2, 3)
*I think the correct thing to say is that arrays are invariant on the type parameter. But I get lost every time I try to understand it properly. 🤯
Adam's answer covers the solution, but it's also worth mentioning why what you're doing doesn't work. Java uses call-site variance annotations, unlike most other languages in existence. Kotlin takes the more traditional approach of using declaration-site variance annotations. That means that, when declaring a class which takes generic arguments, the writer of the class decides how it behaves with respect to subtypes.
Now, Int is a subtype of Int?. Namely, every Int is an Int?, but the reverse is not true. The question is: is Array<Int> a subtype of Array<Int?>? Well, covariant types such as List<T> preserve subtyping, so List<Int> is actually a subtype of List<Int?>. If you replace your example in the question with lists rather than arrays, everything works.
On the other hand, Array<T> is an invariant type. We can both read and write to an array, so it's never safe to upcast or downcast the type parameter. If we could, then the following would typecheck.
// Doesn't compile, for good reason
val myHealthyArray: Array<Int> = arrayOf(1);
val myScaryNullableArray: Array<Int?> = myHealthyArray;
myScaryNullableArray[0] = null;
Now my perfectly innocent myHealthyArray variable has a null in it that the type Array<Int> can't account for. That's contrary to everything Kotlin stands for, so it's disallowed on principle.
If you're only ever going to be using this data structure for reading, not writing, consider using List<T> or something covariant, which better describes the type of your function and also allows the subtyping relationships to work more fully.
I have to store and update the below variables in Kotlin
string name;
Array of Class Objects(5)
Array of Int(5)
C++ format:
struct subject
{
string name;
Array of Class Objects(5)
Array of Int(5)
};
vector<subject> sub;
In other programming languages C/C++ for ex, we use struct and put everything above in that.
Questions:
How to store and update above values with mixture of different types like Array, string, etc., in Kotlin?
Arrays will not get updated in one stretch. Ex: When someone calls AIDL interface with name, I create instance of class and stored the object in array of class obj(0) and integer array(0) as well updated with some value.
When the same AIDL interface is called with same name again, second instance of class will be created and store in **array of class obj(1)**and integer array(1) as well updated. As name is same, there is no need to update it again.
How to check the name and update the other arrays in the run time?
An additional use case, I need to make vector of that struct(according to C++). How I can achieve this in Kotlin?
Instead of a struct you would use a class in Kotlin: https://kotlinlang.org/docs/classes.html. There are several differences between the two that are relevant:
The declaration and class members and there implementation are done in the same place.
The constructor declaration is built into the class declaration.
Kotlin leans towards immutability. While you can reassign fields more often you will see val (like const) and immutable collections.
With that said, you would do something like this to implement your struct in Kotlin. The following isn't a literal 1 for 1 translation, but rather how you might solve your problem with idiomatic Kotlin:
class Subject(val name: String) {
val objects = mutableListOf<NameOfThatClass>()
val numbers = mutableListOf<Int>()
}
What's going on in that code snippet is that we are declaring a class Subject. It has a constructor that takes one argument called name of type String. The val keyword means that the argument will also be kept as a member variable, and that member variable cannot be reassigned. Next, in the class body, we declare and assign two more member variables. objects and numbers will also not be reassignable because of the val keyword, but instead of receiving a constructor argument as a value they receive the result of calling mutableListOf(), which creates more or less the equivalent of a vector. We could also use arrayOfNulls(5) and arrayOfInt(5), but unless you very specifically need fixed-sized arrays it's easier and more common to use lists in Kotlin.
You would then use it like so:
val myName = "foo"
val myFirstObject = ...
val myFirstNumber = 1
val mySubject = Subject(myName)
mySubject.objects += myFirstObject
mySubject.numbers += myFirstNumber
The += you see there isn't an actual reassignment, but an operator overload that acts as Kotlin's equivalent of std::vector's push_back(): https://kotlinlang.org/docs/collection-write.html#adding-elements.
Finally, as mentioned above, Kotlin's lists are what you would normally use in place of vector. However, it sounds like you want to be able to look up a specific entry by name, which is more efficient to do with a map https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/. You could do something like this:
val myMap = mutableMapOf<String, Subject>()
// add to the map like this
myMap[name] = Subject(name)
// get from the map like this (returns null if not in the map)
val mySubject = myMap[name]
// check if the subject is already in the map like this
myMap.containsKey(name)
Then, if you need to iterate over all the Subjects like you would with a vector, you can use myMap.values to get just the Subjects.
Does Kotlin have primitive types?. When I declare the variable: val myAge: Int = 18 then the myAge variable stores the actual values is 18 or stores the addresses of the objects in the memory?. If Int is primitive type then why we can use its method like myAge.minus(10)?
No... and yes.
Kotlin doesn't have primitive type (I mean you cannot declare primitive directly). It uses classes like Int, Float as an object wrapper for primitives.
When kotlin code is converted to jvm code, whenever possible, "primitive object" is converted to java primitive.
In some cases this cannot be done. Those cases are, for example, collection of "primitives". For example, List<Int> cannot contains primitive. So, compiler knows when it can convert object to primitive. And, again, it's very similar to java:
List<Integer> numbers = new ArrayList<>;
numbers.add(0); // <-- you use primitive, but in fact, JVM will convert this primitive to object.
numbers.add(new Integer(0)); // <-- We don't need do that.
Also, when you declare "nullable primitive" it is never converted to primitive (what is kind of obvious, as primitive cannot be null). In java it works very similar:
int k = null; // No way!
Integer kN = null; // That's OK.
One more thing - what docs are saying about it?
For Common, JVM, JS
Represents a 32-bit signed integer. On the JVM, non-nullable values of this type are represented as values of the primitive type int.
For Native
Represents a 32-bit signed integer.
#see: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html
So, the last conclusion. Kotlin doesn't have primitive types out of the box. You treat all objects like objects. Converting to primitive is done at some lower level than code. This design is caused to keep compatibility with JVM.
I did a little deep dive and published it on medium. For interested: https://medium.com/#przemek.materna/kotlin-is-not-primitive-primitives-in-kotlin-and-java-f35713fda5cd
Short answer - yes and depends on the declaration.
val myAge: Int = 18 // this is primitive
val myAge2: Int? = 18 // this is not
There's a very informative video about that
https://www.youtube.com/watch?v=Ta5wBJsC39s
On the Java platform, numbers are physically stored as JVM primitive types, unless we need a nullable number reference (e.g. Int?) or generics are involved. In the latter cases numbers are boxed.
Note that boxing of numbers does not necessarily preserve identity:
val a: Int = 10000
println(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) // !!!Prints 'false'!!!
Note "===" used to compare reference ....
On the other hand, it preserves equality:
val a: Int = 10000
println(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA == anotherBoxedA) // Prints 'true'
In Kotlin we have to distinguish between nullable types and not nullable types. Let's say I have an Array<String?> fom which I know that every value within it is actually not null. Is there an easy way to create an Array<String> from the source array without copying it?
array.requireNoNulls() returns same array Array<T?> with non-optional type Array<T> (But throws IllegalArgmentException if any of the item found null).
if you are sure that your array doesn't have null then you can typecast.
array as Array<String>
Array.filterNotNull might be the safer way to do it. But it will create a new Array.
val items: Array<String?> = arrayOf("one", "two", null, "three")
val itemsWithoutNull: List<String> = items.filterNotNull()
I was learning emptyArray() in Kotlin, but I can't assign values in it (which is for obvious) and neither I can set it's size. What is the use of emptyArray in Kotlin?
There are cases where you want to fallback to an empty array or empty list. For example:
return someInputArray?.filterNotNull() ?: emptyArray()
In this case if I have a valid input array, I filter out null values, otherwise if the source array was null I return an empty array. Therefore an array is always returned instead of a null. Empty lists and arrays are probably more common than passing around nullable lists or arrays in Kotlin.
So yes, it is empty and you cannot add to it, just as no JVM array is expandable once allocated.
Similar to the java.util.Collections.emptyList() methods and its counterparts for Maps, etc., these methods are handy when you are calling a method which takes an array/collection as argument, but you don't want/need to provide any elements in that collection. You can either instantiate a new empty array/collection or use one of the helper methods.
If the above use case is very common in your scenario, you are safing memory by using the helpers as always the same instance is reused instead of creating new instances again and again. Otherwise it's mainly "syntax candy" making your code more readable and easier to understand.
emptyArray() function returns an empty array of size 0. it doesn't take any paramters (Nor size, neither elements). you can use it as rvalue in assignment operations. You can use empty array to dump all the values in a pre-existing arrays and set it's size to 0.
Note: it is better to return an empty than returning an array of nulls, as it'll not create any null point exceptions in further operations.
var array=arrayOf(1,2,3,4,5);
array = emptyArray() //The array datais dumped and size is set to 0;
array = arrayOf(0,1,2)
Arrays are fixed size containers. The emptyArray() function creates an array of 0 length, and you really can't do much with this. You can't store anything in it, and you can't resize it.
A common use case where you need an empty array would be as a default value for a property that will be set to a different array at a later point. This can be better than storing null in that property by default, because you don't have to deal with handling the possible null value when your code uses the array. For example, you can safely iterate over an empty array.
For a simple example:
class NumberHolder {
var numbers: Array<Int> = emptyArray()
fun printNumbers() {
numbers.forEach { println(it) }
}
}
The usage of this class would look something like this:
val nh = NumberHolder()
nh.printNumbers() // prints nothing
nh.numbers = arrayOf(1, 2, 3)
nh.printNumbers() // prints 1, 2, and 3 on separate lines