In Kotlin/Native, what is the correct way to create and initialize an array of a structure? My code interfaces with a C library that defines the relevant structures as:
typedef struct VkDeviceQueueCreateInfo {
...
} VkDeviceQueueCreateInfo;
typedef struct VkDeviceCreateInfo {
...
uint32_t queueCreateInfoCount;
const VkDeviceQueueCreateInfo* pQueueCreateInfos;
...
} VkDeviceCreateInfo;
I've created wrapper classes DeviceQueueCreateInfo and DeviceCreateInfo. The Kotlin bindings are generated as classes inheriting from CStructVar and used like this:
class DeviceQueueCreateInfo(...) {
// Allocates in `scope` and fills a `VkDeviceQueueCreateInfo`
fun toRaw(scope: MemScope): VkDeviceQueueCreateInfo = ...
}
class DeviceCreateInfo(val queueCreateInfos: List<DeviceQueueCreateInfo>) {
// Allocates in `scope` and fills a `VkDeviceCreateInfo`
fun toRaw(scope: MemScope) = with(scope) {
alloc<VkDeviceCreateInfo>().also {
it.queueCreateInfoCount = queueCreateInfos.size.toUInt()
it.pQueueCreateInfos = ??? // Allocate array of struct in `scope`
}
}
}
I've added a ??? to the code to show where I'm having trouble. Kotlin NativePlacement has allocArray<T>(length: Int), so that was obviously my first stop:
it.pQueueCreateInfos = allocArray(queueCreateInfos.size)
And then to initialize them I tried:
it.pQueueCreateInfos = allocArray<VkDeviceQueueCreateInfo>(queueCreateInfos.size)
.also { arr ->
queueCreateInfos.forEachIndexed { index, x -> arr[index] = x.toRaw(scope) }
}
However, this fails to compile with error No set method providing array access at arr[index] = x. I wrote the following code which compiles and runs as expected:
val floats = listOf(1f, 2f, 3f)
allocArray<FloatVar>(floats.size).also { arr ->
floats.forEachIndexed { index, x -> arr[index] = x }
}
The code is identical apart from the type used, leading me to believe that I was perhaps trying to assign to an rvalue. I went looking for VkDeviceQueueCreateInfoVar only to find this:
Also, any C type has the Kotlin type representing the lvalue of this type, i.e., the value located in memory rather than a simple immutable self-contained value. Think C++ references, as a similar concept. For structs (and typedefs to structs) this representation is the main one and has the same name as the struct itself, for Kotlin enums it is named ${type}Var, for CPointer it is CPointerVar, and for most other types it is ${type}Var.
This states that for structs, the lvalue representation has the same name as the struct (no Var suffix)... so VkDeviceQueueCreateInfo should represent an assignable lvalue, and I'm confused as to why I am unable to assign values to my array. It occurs to me that Kotlin's assignment does something very different to a C assignment, but I had assumed there would be an idiomatic way to perform a structure assignment.
I've looked through the other overloads and methods in NativePlacement to find one that allows me to initialize the values in the newly created array, and I found allocArray<T>(length: Long, initializer: T.(index: Long)->Unit), but this seems to suffer from the same problem.
How do I allocate and initialize an array of structures through cinterop?
unsigned data types could be nice for array access. Usually the indexes are unsigned anyway. But currently I cannot directly do this. E.g. this code.
val foo = 1.toUInt()
"foo"[foo]
fails to compile with:
error: type mismatch: inferred type is UInt but Int was expected
what is the best way to deal with this? Sure I could do:
val foo = 1.toUInt()
"foo"[foo.toInt()]
but this feels wrong somehow. UInt is an inline class anyway and gets erased to Int anyway - so I think this should not be needed. Anyone saw a kotlin/KEEP for this?
Also wondering about how to define unsigned constants. Unfortunately the constructor is private so I cannot do e.g.
const val foo = UInt(42)
and
const val foo = 42.toUInt()
fails with 42.toUInt() is not a constant value
Unless/until there's built-in support for this, you can easily add it yourself. For example, for standard arrays:
operator fun <T> Array<T>.get(index: UInt) = this[index.toInt()]
And for CharSequences (which aren't arrays):
operator fun CharSequence.get(index: UInt) = this[index.toInt()]
With that in scope, your "foo"[foo] works fine!
(You'd also need separate overloads for IntArray &c if you used those.)
In the array indexing question, .toInt() is the best method I have found.
Declaring a const, you can append a "u" to any integer constant, or "uL" for a long constant, like 42u or 1_000_000_000_000uL.
As I know Java is pass-by-value from this post. I am from Java background I wonder what Kotlin is using for passing values in between. Like in Extensions or Methods etc.
Every time I hear about the "pass-by-value" vs "pass-by-reference" Java debate I always think the same. The answer I give: "Java passes a copy (pass-by-value) of the reference (pass-by-reference)". So everyone is happy. I would say Kotlin does the same as it is JVM based language.
UPDATE
OK, so it's been a while since this answer and I think some clarification should be included. As #robert-liberatore is mentioning in the comments, the behaviour I'm describing is true for objects. Whenever your methods expect any object, you can assume that the JVM internally will make a copy of the reference to the object and pass it to your method. That's why having code like
void doSomething(List<Integer> x) {
x = new ArrayList<Integer>()
}
List<Integer> x = Arrays.asList(1, 2, 3);
doSomething(x);
x.length() == 3
behaves like it does. You're copying the reference to the list, so "reassigning it" will take no effect in the real object. But since you're referring to the same object, modifying its inner content will affect the outer object.
This is something you may miss when defining your attributes as final in order to achieve immutability. You won't be able to reassign them, but there's nothing preventing you from changing its content
Of course, this is true for objects where you have a reference. In case of primitives, which are not a reference to an object containing something but "something" themselves, the thing is different. Java will still make a copy of the whole value (as it does with the whole reference) and pass it to the method. But primitives are just values, you can't "modify its inner values". So any change inside a method will not have effect in the outer values
Now, talking about Kotlin
In Kotlin you "don't have" primitive values. But you "do have" primitive classes. Internally, the compiler will try to use JVM primitive values where needed but you can assume that you always work with the boxed version of the JVM primitives. Because of that, when possible the compiler will just make a copy of the primitive value and, in other scenarios, it will copy the reference to the object. Or with code
fun aJvmPrimitiveWillBeUsedHere(x: Int): Int = x * 2
fun aJvmObjectWillBeUsedHere(x: Int?): Int = if (x != null) x * 2 else 1
I'd say that Kotlin scenario is a bit safer than Java because it forces its arguments to be final. So you can modify its inner content but not reassign it
fun doSomething(x: MutableList<Int>) {
x.add(2) // this works, you can modify the inner state
x = mutableListOf(1, 2) // this doesn't work, you can't reassign an argument
}
It uses the same principles like Java. It is always pass-by-value, you can imagine that a copy is passed. For primitive types, e.g. Int this is obvious, the value of such an argument will be passed into a function and the outer variable will not be modified. Please note that parameters in Kotlin cannot be reassigned since they act like vals:
fun takeInt(a: Int) {
a = 5
}
This code will not compile because a cannot be reassigned.
For objects it's a bit more difficult but it's also call-by-value. If you call a function with an object, a copy of its reference is passed into that function:
data class SomeObj(var x: Int = 0)
fun takeObject(o: SomeObj) {
o.x = 1
}
fun main(args: Array<String>) {
val obj = SomeObj()
takeObject(obj)
println("obj after call: $obj") // SomeObj(x=1)
}
You can use a reference passed into a function to change the actual object.
The semantics is identical to Java.
In Java, when you have an instance of an object, and you pass it to a method, that method can change the state of that object, and when the method is done, the changes would have been applied to the object at the call site.
The same applies in Kotlin.
For primitives value is passed, and for non-primitives a reference to the object is passed. I'll explain with an example:
The code:
fun main() {
var a = 5
var b = a
a = 6
println("b = $b")
}
prints: b = 5
Kotlin passes the value of a to b, because a is a primitive. So changing a afterwards won't impact b.
The code:
fun main() {
var a = Dog(5)
var b = a
a.value = 6
println("b = ${b.value}")
}
class Dog (var value: Int)
prints b = 6, because this time a is not a primitive and so the reference to the object (Dog) was passed to b and not its value. Therefore changing a would affect all objects that point to it.
In Java primitive types like int, float, double, boolean are passed to a method by value, if you modify them inside the receiver method they doesn't change into the calling method. But if the property/variable type isn't a primitive, like arrays of primitives or other classes when they are changed inside the method that receive them as parameter they also change in the caller method.
But with Kotlin nothing seems to be primitive, so I think all is passed by reference.
This might be a little bit confusing.
The correct answer, IMHO, is that everything passes by reference, but no assignment is possible so it will be similar to passing by value in C++.
Note that function parameters are constant, i.e., they cannot be assigned.
Remember that in Kotlin there are no primitive types. Everything is an object.
When you write:
var x: Int = 3
x += 10
You actually create an object of type Int, assign it the value 3, and get a reference, or pointer, named x.
When you write
x += 10
You reassign a new Int object, with the value 13, to x. The older object becomes a garbage (and garbage-collected).
Of course, the compiler optimizes it, and creates no objects in the heap in this particular case, but conceptually it is as explained.
So what is the meaning of passing by reference function parameters?
Since no assignment is possible for function parameters, the main advantage of passing by reference in C++ does not exist in Kotlin.
If the object (passed to the function) has a method which changes its internal state, it will affect the original object.
No such method exists for Int, String, etc. They are immutable objects.
No copy is ever generated when passing objects to functions.
Bear in mind, am quite new to Kotlin. In my opinion, primitives are passed-by-value, but objects are passed-by-reference.
A primitive passed to a class works by default, but if you pass an object from a list, for example, and that object changes, the class object changes too. Because, in fact, it is the same object.
Additionally, if objects gets removed from the list, the class object IS STILL A REFERENCE. So it can still change due to references in other places.
Example below explaines. You can run it here.
fun main() {
val listObjects = mutableListOf(ClassB(), ClassB(), ClassB())
val listPrimitives = mutableListOf(111, 222, 333)
val test = ClassA()
test.ownedObject = listObjects[0]
test.ownedPrimitive = listPrimitives[0]
println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " +
test.ownedPrimitive)
listObjects[0].isEnabled = true
println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " +
test.ownedPrimitive)
listPrimitives[0] = 999
println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " +
test.ownedPrimitive)
}
class ClassA {
var ownedObject: ClassB = ClassB()
var ownedPrimitive: Int = 0
}
class ClassB {
var isEnabled = false
}
Since Kotlin is a new language for JVM, like Java it is pass-by-value. The confusing part is with object, at first it looks like that it is passed-by-reference but the actuality is that the reference/pointer itself is pass-by-value (a copy of a reference is passed to a method) hence when a method receives a reference to an object, the method can manipulate the original object.
For example, FastUtil's IntArrayList has a push method that accepts both int (primitive) and Integer (boxed), but Kotlin sees these both as the same function push(Int), therefore I cannot use the function at all as the function is ambiguous.
What should I do when a Java library has overloads for both the primitive and boxed type?
(p.s. I am aware that I can use the add(int) method. I am in search of what to do if I come across such a problem in the future.)
Consider these methods in Java:
void f(int x) { }
void f(Integer y) { }
In Kotlin, they are seen as
f(x: Int)
f(x: Int!)
The second method has a parameter of platform type, meaning it might be nullable, corresponding to Integer.
First one can be simply called with Kotlin Int passed:
f(5) // calls f(int x)
To call the second one, you can cast the argument to nullable Int?, thus selecting the overload:
f(5 as Int?) // calls f(Integer y)
Have you tried writing a Java class to serve as an intermediary? That is, write your own java class with the method you want Kotlin to see, then call that method from your Kotlin code.
Can someone please explain me the following code snippet?
value struct ValueStruct {
int x;
};
void SetValueOne(ValueStruct% ref) {
ref.x = 1;
}
void SetValueTwo(ValueStruct ref) {
ref.x = 2;
}
void SetValueThree(ValueStruct^ ref) {
ref->x = 3;
}
ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);
ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?
ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?
And my second question is: is there any reason to have something like that?:
ref struct RefStruct {
int x;
};
RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;
// can I retrieve my handle from ref?
// RefStruct^ myref = ???
What is more: I see no difference between value type and ref type, since both can be pointed by handler ;(
Remember that the primary use of C++/CLI is for developing class libraries for consumption by GUIs / web services built in other .NET languages. So C++/CLI has to support both reference and value types because other .NET languages do.
Furthermore, C# can have ref parameters that are value typed as well, this isn't unique to C++/CLI and it doesn't in any way make value types equivalent to reference types.
To answer the questions in your code comments:
am I creating a copy or what?
Yes, SetValueTwo takes its parameter by value, so a copy is made.
is this copy Disposable even though value types don't have destructors?
Incorrect. Value types can have destructors. Value types cannot have finalizers. Since this particular value type has a trivial destructor, the C++/CLI compiler will not cause it to implement IDisposable. In any case, if a parameter is an IDisposable value type, the C++/CLI compiler will ensure that Dispose is called when the variable goes out of scope, just like stack semantics for local variables. This includes abnormal termination (thrown exception), and allows managed types to be used with RAII.
Both
ValueStruct% ref = *gcnew ValueStruct;
and
ValueStruct^ ref = gcnew ValueStruct;
are allowed, and put a boxed value type instance on the managed heap (which isn't a heap at all, but a FIFO queue, however Microsoft chooses to call it a heap like the native memory area for dynamic allocation).
Unlike C#, C++/CLI can keep typed handles to boxed objects.
If a tracking reference is to a value type instance on the stack or embedded in another object, then the value type content has to be boxed in the process of formed the reference.
Tracking references can also be used with reference types, and the syntax to obtain a handle is the same:
RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;
RefClass stacksem;
RefClass^ ssh = %stacksem;
One thing that I can never seem to remember completely is that the syntax isn't 100% consistent compared to native C++.
Declare a reference:
int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference
Declare a pointer:
int* pi; // native
Stream^ sh; // tracking handle
Form a pointer:
int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object
Note that the unary address-of operator is the same as the reference notation in both standard C++ and C++/CLI. This seems to contradict a tracking reference cannot be used as a unary take-address operator (MSDN) which I'll get back to in a second.
First though, the inconsistency:
Form a reference from a pointer:
int& iref = *pi;
DateTime% dtref = *dth;
Note that the unary dereference operator is always *. It is the same as the pointer notation only in the native world, which is completely opposite of address-of which, as mentioned above, are always the same symbol as the reference notation.
Compilable example:
DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
FileInfo fi("temp.txt");
// FileInfo^ fih = &fi; causes error C3072
FileInfo^ fih = %fi;
Now, about unary address-of:
First, the MSDN article is wrong when it says:
The following sample shows that a tracking reference cannot be used as a unary take-address operator.
The correct statement is:
% is the address-of operator for creation of a tracking handle. However its use is limited as follows:
A tracking handle must point to an object on the managed heap. Reference types always exist on the managed heap so there is no problem. However, value types and native types may be on the stack (for local variables) or embedded within another object (member variables of value type). Attempts to form a tracking handle will form a handle to a boxed copy of the variable: the handle is not linked to the original variable. As a consequence of the boxing process, which requires metadata which does not exist for native types, it is never possible to have a tracking handle to an instance of a native type.
Example code:
int i = 5;
// int^ ih = %i; causes error C3071
System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance
// of a ref class or a value-type
If System::Int32 isn't a value type then I don't know what is. Let's try System::DateTime which is a non-primitive value type:
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
This works!
As a further unfortunate restriction, primitive types which have dual identity (e.g. native int and managed value type System::Int32) are not handled correctly, the % (form tracking reference) operator cannot perform boxing even when the .NET name for the type is given.