Pass value from Kotlin/native to C - kotlin

How do I pass a value from Kotlin to C as an int* and receive the written value? The C function looks like this:
int readValue(long param, int *value);
The return value is just 1 or 0 indicating success or failure. The actual value that was read is passed back through the value pointer. I tried wrapping a Kotlin Int with cValuesOf:
import interop.readValue
fun doIt(): Boolean {
val arg = cValuesOf(0) // This should give me a CValue<Int>, right?
val result = readValue(42L, arg) // Here I call the C function
if (result == 0) {
return false
} else {
println("Read value: ${arg.value}") // doesn't work, there is no arg.value
return true
}
}
But I can't get the result out from it after the call. How do I do this properly?

Because Kotlin doesn't allocate variables on the stack as C does, you need to allocate an int* as a Kotlin IntVarOf<Int> on the heap. memScoped() provides a memory scope where allocated memory will be automatically deallocated at the end of the lambda block.
fun doIt(): Boolean {
return memScoped {
val arg = alloc<IntVar>()
val result = readValue(42L, arg.ptr)
if (result == 0) {
false
} else {
println("Read value: ${arg.value}")
true
}
}
}

Related

How to return boolean when using coroutines kotlin

I get the error The boolean literal does not conform to the expected type Unit when run code. Please help me fix it
public suspend fun RequireDevice(manager: UsbManager, device: UsbDevice): UsbDevice? {
// 多重要求にならないようにする - Tránh nhiều yêu cầu
if(permissionContinuation != null)
return null
// requestPermissionを実行
val device = suspendCoroutine<UsbDevice?> {
manager.requestPermission(device, mPermissionIndent)
permissionContinuation = it
}
// continuationを消去
permissionContinuation = null
return device
}
function selectDevice
fun selectDevice(vendorId: Int, productId: Int): Boolean {
if ((mUsbDevice == null) || (mUsbDevice!!.vendorId != vendorId) || (mUsbDevice!!.productId != productId)) {
closeConnectionIfExists()
connectScope.launch label#{
val usbDevices: List<UsbDevice> = deviceList
for (usbDevice: UsbDevice in usbDevices) {
if ((usbDevice.vendorId == vendorId) && (usbDevice.productId == productId)) {
Log.v(LOG_TAG, "Request for device: vendor_id: " + usbDevice.vendorId + ", product_id: " + usbDevice.productId)
closeConnectionIfExists()
val grantedDevice = RequireDevice(mUSBManager!!, usbDevice)
if (grantedDevice != null){
Log.v(LOG_TAG, "Connected")
state = STATE_USB_CONNECTING
mHandler?.obtainMessage(STATE_USB_CONNECTING)?.sendToTarget()
return#label true
}
else{
Log.v(LOG_TAG, "Connection failed.")
return#label false
}
}
}
}
} else {
mHandler?.obtainMessage(state)?.sendToTarget()
return true
}
}
BroadcastReceiver
private val mUsbDeviceReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if ((ACTION_USB_PERMISSION == action)) {
synchronized(this) {
val usbDevice: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
Log.i(
LOG_TAG,
"Success get permission for device ${usbDevice?.deviceId}, vendor_id: ${usbDevice?.vendorId} product_id: ${usbDevice?.productId}"
)
mUsbDevice = usbDevice
openConnection()
permissionContinuation!!.resume(usbDevice)
state = STATE_USB_CONNECTED
mHandler?.obtainMessage(STATE_USB_CONNECTED)?.sendToTarget()
} else {
permissionContinuation!!.resume(null)
Toast.makeText(context, "User refused to give USB device permission: ${usbDevice?.deviceName}", Toast.LENGTH_LONG).show()
state = STATE_USB_NONE
mHandler?.obtainMessage(STATE_USB_NONE)?.sendToTarget()
}
}
} else if ((UsbManager.ACTION_USB_DEVICE_DETACHED == action)) {
if (mUsbDevice != null) {
Toast.makeText(context, "USB device has been turned off", Toast.LENGTH_LONG).show()
closeConnectionIfExists()
state = STATE_USB_NONE
mHandler?.obtainMessage(STATE_USB_NONE)?.sendToTarget()
}
} else if ((UsbManager.ACTION_USB_DEVICE_ATTACHED == action)) {
}
}
}
Error:
e:USBPrinterService.kt: (139, 42): The boolean literal does not conform to the expected type Unit
Error 2:
e:USBPrinterService.kt: (143, 42): The boolean literal does not conform to the expected type Unit
Error 3:
e:USBPrinterService.kt: (154, 5): A 'return' expression required in a function with a block body ('{...}')
The boolean literal does not conform to the expected type Unit
You're facing this error because the lambda passed to launch is not expected to return any useful value. Its return type is Unit, which is used in functions for which we don't expect any particular result, and you're trying to return a Boolean out of it, which doesn't match the return type.
In order to return a value, you would need to use async instead of launch. This way, the lambda can indeed return a value (here, a Boolean), and the async function itself will return a Deferred<Boolean> representing the future boolean value that will get when the task completes. However, there is a deeper problem here that you need to understand first.
You have to understand that this function signature denotes a synchronous function:
fun selectDevice(vendorId: Int, productId: Int): Boolean {
...
}
It means it blocks the calling thread until the result is returned, because it's not suspend and the Boolean value is returned directly (not via a callback or a Future or Deferred).
However, inside this function, you're trying to launch an asynchronous task (with the launch function), but you somehow still want to return the result from it. That's not how launch works. Because the task is asynchronous, the call to launch returns before the task is completed, and possibly even before the task starts at all. As we've also seen above, launch doesn't return any value itself. In fact, even if you change it to async, the async { .. } function call will not return the value directly, but a Deferred<Boolean> (as we've seen). This wrapper would be returned immediately (before the task completes or even starts), so you would then have to wait for this value to be ready somehow anyway.
Basically, with the signature you chose for selectDevice, you don't have a choice but to block the current thread until the value is ready, which kinda defeats the purpose of coroutines. Instead, it would be best if you made selectDevice a suspend function itself, so you can call suspend functions inside without launching new coroutines.
If you want to stick with the blocking signature, then you have to block the thread to wait for the value, for instance using runBlocking { deferred.await() }.

Kotlin Contracts not working for null-check in extension function

I'm trying to write an extension function that returns true if the value is not null or 0 and use a contract to guarantee to the compiler that if I return true, the value is non-null. However, it doesn't seem to be working with smart casting. It still won't compile when I try to pass the value into a function that takes a non-nullable Long.
I tried to compile this code and it would not work. I expected the id to be smart-casted to a Long from a Long? since the contract guarantees that if isValidId returns true then the passed in Long? is not null.
As you can see, the property is immutable, so I don't think that's the issue. I also added some more code below, because the problem appears to be specific to extension functions. It works when I pass ID as a traditional parameter.
fun test() {
val id: Long? = null //5L
if (id.isValidID()) {
// It won't compile because the compiler says that id is a Long?
// instead of smart casting it to a Long. doWithId requires a Long.
doWithId(id)
}
}
fun doWithId(id: Long) {}
#OptIn(ExperimentalContracts::class)
fun Long?.isValidID(): Boolean {
contract { returns(true) implies (this#isValidID != null) }
return this != null && this != 0L
}
Thanks!
EDIT:
Oh! It works when it's not an extension function. Does anybody know how I can make extension functions work?
fun test() {
val id: Long? = null
if (isValidID(id)) {
// This compiles now that I pass ID as a param instead of
// passing it in an extension function.
doWithId(id)
}
}
fun doWithId(id: Long) {}
#OptIn(ExperimentalContracts::class)
fun isValidID(id: Long?): Boolean {
contract { returns(true) implies (id != null) }
return id != null && id != 0L
}

How to handle nullable types in generic class

I want to write a Promise class in kotlin. This class uses a generic type. The type can also be a nullable type. When I call the consumer, the value can be null, if the genereic type is nullable. If not the value must be set to an object. The kotlin compiler shows me following message:
Smart cast to 'T' is impossible, because 'value' is a mutable property that could have been changed by this time
I understand why this message appears but I am sure, that the value must be correct at this moment. How can I compile this class? I tried to force to access the value with !! but then my test with null will fail with a NPE.
java.lang.NullPointerException
at test.Promise.resolve(App.kt:20)
at test.AppTest.testPromiseNull(AppTest.kt:31)
class Promise<R> {
private var resolved = false
private var value: R? = null
var then: Consumer<R>? = null
fun resolve(r: R) = synchronized(this) {
if (resolved) error("Promise already resolved!")
value = r
resolved = true
then?.accept(value) // Smart cast to 'T' is impossible, because 'value' is a mutable property that could have been changed by this time*
}
fun then(consumer: Consumer<R>) = synchronized(this) {
if (then != null) error("Just one consumer is allowed!")
then = consumer
val value = value
if (resolved) {
consumer.accept(value) // Smart cast to 'T' is impossible, because 'value' is a mutable property that could have been changed by this time*
}
}
}
#Test fun testPromise() {
val promise = Promise<String>()
var resolved = false
promise.then {
assertEquals(it, "hello" )
resolved = true
}
promise.resolve("hello")
assert(resolved)
}
#Test fun testPromiseNull() {
val promise = Promise<String?>()
var resolved = false
promise.then {
assertNull(it)
resolved = true
}
promise.resolve(null)
assert(resolved)
}
UPDATE
I created a little help function
private fun <T> uncheckedCast(t: T?): T {
#Suppress("UNCHECKED_CAST")
return t as T
}
For your resolve function, you already have the immutable parameter value you can use instead.
fun resolve(r: R) = synchronized(this) {
if (resolved) error("Promise already resolved!")
value = r
resolved = true
then?.accept(r)
}
In the other case, since you know more than the compiler, you can do an explicit cast, and suppress the warning.
fun then(consumer: Consumer<R>) = synchronized(this) {
if (then != null) error("Just one consumer is allowed!")
then = consumer
if (resolved) {
#Suppress("UNCHECKED_CAST")
consumer.accept(value as R)
}
}

why Kotlin inline function params is must not be null

inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: (() -> Unit)? = null) {
if (value != null) {
notNullBlock(value)
} else {
if(isNullBlock != null){
isNullBlock()
}
}
}
I tried to write some higher-order functions to facilitate development, but it is error
I think it is related to how inline functions and lambdas passed to it are inlined. The inline modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site. It seems Kotlin doesn't allow to use nullable lambdas.
If you want some default value for isNullBlock parameter you can use empty braces isNullBlock: () -> Unit = {}:
inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: () -> Unit = {}) {
if (value != null) {
notNullBlock(value)
} else {
isNullBlock()
}
}
There is a great post explaining how inline works from Android Developer Advocate Florina Muntenescu. Following all of the explanations it should be clear why nullable lambdas are not allowed.
In short:
Because of the inline keyword, the compiler copies the content of the inline function to the call site, avoiding creating a new Function object.
That is the performance benefit inline keyword gives us. But in order to do that compiler must be sure that you always pass in a lambda argument whether it is empty or not. When you try to make the lambda argument nullable compiler will not be able to copy the content of a null lambda to the call site. Similarly, you cannot execute compare operations like != null or use ? to unwrap the optional lambda that should be inlined because when compiled there will be no lamda/function objects. More explanation below.
Example (long explanation)
In my examples your function is updated and takes empty lambda as default arguments for isNullBlock:
inline fun <T, R> isNullObject(value: T?, notNullBlock: (T) -> R, isNullBlock: (() -> Unit) = {}) {
if (value != null) {
notNullBlock(value)
} else {
isNullBlock()
}
}
Here is usage of not inlined version of your isNullObject function decompiled to Java.
Kotlin code
class Test {
init {
isNullObject(null as? Int,
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
isNullObject(0,
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
}
}
Decompiled Java code
public final class Test {
public Test() {
TestKt.isNullObject((Integer)null, (Function1)null.INSTANCE, (Function0)null.INSTANCE);
TestKt.isNullObject(0, (Function1)null.INSTANCE, (Function0)null.INSTANCE);
}
}
As you can see nothing too unusual happens (though, it is hard to understand what null.INSTANCE is). Your isNullObject function called with three arguments passed as defined in Kotlin.
Here is how your inlined function will decompile using the same Kotlin code.
public final class Test {
public Test() {
Object value$iv = (Integer)null;
int $i$f$isNullObject = false;
int var3 = false;
String var4 = "isNullBlock called";
boolean var5 = false;
System.out.println(var4);
int value$iv = false;
$i$f$isNullObject = false;
int var8 = false;
String var9 = "notNullBlock called";
boolean var6 = false;
System.out.println(var9);
}
}
For the first function call, we immediately get if (value != null) statement resolved as false and notNullBlock passed in is not even ended up in the final code. At runtime, there will be no need to check each time if the value is null or not. Because the isNullObject is inlined with its lambdas there is no Function objects generated for lambda arguments. It means there is nothing to check for nullability. Also, this is the reason why you cannot hold a reference to the lambda/function arguments of the inlined function.
Object value$iv = (Integer)null;
int $i$f$isNullObject = false;
int var3 = false;
String var4 = "isNullBlock called";
boolean var5 = false;
System.out.println(var4);
But inlining works only if compiler is able to get values of given arguments at compile time. If instead of isNullObject(null as? Int, ...) and isNullObject(0, ...) the first argument was a function call - inlining would give no benefit!
When compiler cannot resolve if statement
A function added - getValue(). Returns optional Int. The compiler does not know the result of getValue() call ahead of time as it can be calculated only at runtime. Thus inlining does only one thing - copies full content of the isNullObject into Test class constructor and does it twice, for each function call. There is a benefit still - we get rid of 4 Functions instances created at runtime to hold the content of each lambda argument.
Kotlin
class Test {
init {
isNullObject(getValue(),
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
isNullObject(getValue(),
{
println("notNullBlock called")
it
},
{ println("isNullBlock called") })
}
fun getValue(): Int? {
if (System.currentTimeMillis() % 2 == 0L) {
return 0
} else {
return null
}
}
}
Decompiled Java
public Test() {
Object value$iv = this.getValue();
int $i$f$isNullObject = false;
int it;
boolean var4;
String var5;
boolean var6;
boolean var7;
String var8;
boolean var9;
if (value$iv != null) {
it = ((Number)value$iv).intValue();
var4 = false;
var5 = "notNullBlock called";
var6 = false;
System.out.println(var5);
} else {
var7 = false;
var8 = "isNullBlock called";
var9 = false;
System.out.println(var8);
}
value$iv = this.getValue();
$i$f$isNullObject = false;
if (value$iv != null) {
it = ((Number)value$iv).intValue();
var4 = false;
var5 = "notNullBlock called";
var6 = false;
System.out.println(var5);
} else {
var7 = false;
var8 = "isNullBlock called";
var9 = false;
System.out.println(var8);
}
}

How and when does kotlin let run?

for all the examples on the internet i cant figure out when and how is kotlins let ran?
if(phones.size == 0){
phones.add("")
}
return phones[0]
so if phones list size is 0, we add empty string and return that instead.
Now how would one do same with let ?
phones.let {
return ""
}
does this work with size 0, or do i have to have null list?
do i need return keyword, if yes, where?
is the above fun always going to return empty string? or just when phones is null?
when is this let code block even ran?
Update:
val cakes = listOf("carrot", "cheese", "chocolate")
fun main(args: Array<String>) {
var cakesEaten = 0
while (cakesEaten < 3) { // 1
cakesEaten ++
val result = cakes?.let{
if(cakesEaten == 2) {
"HeyLo"
} else {
2
}
}
println("result value = $result")
when(result) {
is String -> println(" result variable is a String")
is Int -> println(" result variable is Integer")
}
}
}
result value = 2
result variable is Integer
result value = HeyLo
result variable is a String
result value = 2
result variable is Integer
Original post
If your 'phones' Object is a Nullable type,
val result = phones?.let{
// this block runs only if phones object is not null
// items can be accessed like it.size
// expression result will be returned. no need to mention return.
if(it.size == 0) {
it.add("")
it[0]
} else it.size
}
result value will be either it[0] or it.size and its type will be Any.
But if this the functionality you need you can check Markos solution.
If you're interested in how to write your logic in Kotlin's FP idiom, it doesn't involve let at all:
phones.takeIf { it.isEmpty() }?.add("")
return phones[0]
However, I don't find this idiom better than what you started out with.