https://kotlinlang.org logo
#compiler
Title
# compiler
r

reactormonk

07/04/2022, 7:26 AM
I think I'm already hitting the limits of the compiler... Wrapping an API into coroutines:
Copy code
suspend fun <ReaderType, ReturnType> registerCallback(listener: (((ReaderType) -> Unit)?) -> Unit, func: (ReaderType) -> ReturnType): ReturnType {
    return suspendCoroutine<ReturnType> { block ->
        listener { btr ->
            block.resume(func(btr))
            listener(null)
        }
    }
}

val reader = registerCallback(acsBluetoothReaderManager::setOnReaderDetectionListener) { reader ->
  [...]
  reader
}
gives me
Copy code
java.lang.ClassCastException: org.reactormonk.debugapplication.BluetoothSupportKt$registerCallback$2$1 cannot be cast to com.acs.bluetooth.BluetoothReaderManager$OnReaderDetectionListener
        at org.reactormonk.debugapplication.BluetoothNFCActivity$onCreate$1$reader$1.invoke(BluetoothNFC.kt:72)
Compiles fine though. This is the interface:
Copy code
public void setOnReaderDetectionListener(BluetoothReaderManager.OnReaderDetectionListener listener) {
        this.b = listener;
    }

    public interface OnReaderDetectionListener {
        void onReaderDetection(BluetoothReader var1);
    }
g

Grégory Lureau

07/04/2022, 7:44 AM
Weird, it should not compile afaik. Your lambda is not actually implementing OnReaderDetectionListener, so in
registerCallback
when you call
listener { ... }
you implement a method with a signature that looks like the interface ORDL but is not an implementation of it, and I think it matches the ClassCastException error. You may try with a functional interface but I think it'll be the same issue eventually (for the JVM build at least).
If you want to use lambdas, why not removing the interface instead?
Copy code
public void setOnReaderDetectionListener(listener: ((BluetoothReader) -> Unit)?) {
        this.b = listener;
    }
(Also tbh I'm not sure what you're trying to achieve with the registerCallback method 🤔 )
r

reactormonk

07/04/2022, 7:46 AM
Can't modify that part of the code, proprietary jar 😞
It's a weird interface, where you a) gotta register a callback for when the hardware gets back to you (that's the listener part) b) call the method. The example here is only a), this is the big brother:
Copy code
suspend fun <ReaderType, InputType, OutputType, ReturnType> convertToCallback(
    funCall: (InputType) -> Boolean,
    listener: (((ReaderType, OutputType, Int) -> Unit)?) -> Unit,
    input: InputType,
    outputParser: (OutputType) -> ReturnType
): ReturnType {
    return suspendCoroutine<ReturnType> { block ->
        if (funCall(input)) {
            listener { _, output, errorCode ->
                if (errorCode == 0) {
                    block.resume(outputParser(output))
                } else {
                    block.resumeWithException(ReaderCommandException("Error code from reader: $errorCode"))
                }
                listener(null)
            }
        } else {
            block.resumeWithException(ReaderCommandException("Couldn't send command. Bonded?"))
        }
    }
}
Yes, I've written Haskell professionally before. Does it show? This is the full selection of interfaces I'm trying to abstract over:
Copy code
public interface OnEnableNotificationCompleteListener {
        void onEnableNotificationComplete(BluetoothReader var1, int var2);
    }

    public interface OnResponseApduAvailableListener {
        void onResponseApduAvailable(BluetoothReader var1, byte[] var2, int var3);
    }

    public interface OnEscapeResponseAvailableListener {
        void onEscapeResponseAvailable(BluetoothReader var1, byte[] var2, int var3);
    }

    public interface OnDeviceInfoAvailableListener {
        void onDeviceInfoAvailable(BluetoothReader var1, int var2, Object var3, int var4);
    }

    public interface OnCardStatusChangeListener {
        void onCardStatusChange(BluetoothReader var1, int var2);
    }

    public interface OnCardStatusAvailableListener {
        void onCardStatusAvailable(BluetoothReader var1, int var2, int var3);
    }

    public interface OnCardPowerOffCompleteListener {
        void onCardPowerOffComplete(BluetoothReader var1, int var2);
    }

    public interface OnAuthenticationCompleteListener {
        void onAuthenticationComplete(BluetoothReader var1, int var2);
    }

    public interface OnAtrAvailableListener {
        void onAtrAvailable(BluetoothReader var1, byte[] var2, int var3);
    }
Maybe I'm approaching this by shoehorning a specific way into Kotlin, what would be a decent way to put some
suspend
into it?
4 Views