Inherit function type in Kotlin

610 Views Asked by At

Is there a way in Kotlin to inherit function types? What I want is to have a member like so: private lateinit var onPickedFunc: (Any) -> Task<Void>? so I can dynamically store the functions I need to run after a user has made it's choice. For example:

private fun showImagePicker(func: (Uri) -> Task<Void>?) {
        onPickedFunc = func
        val intent =
            Intent(
                Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI
            )
        startActivityForResult(intent, RC_PICK_IMAGE)
    }

private fun showMenu(func: (Context) -> Task<Void>?, v: View) {
        onPickedFunc = func
        PopupMenu(context, v).apply {
            // ProfileFragment implements OnMenuItemClickListener
            setOnMenuItemClickListener(this@ProfileFragment)
            inflate(R.menu.profile_settings_menu)
            show()
        }
    }

I did find a group of classes called Function, but none of them allow inheritance in the input parameter (one of them allows inheritance in the output parameter: Function<out R>). Is there any way to achieve that? Thanks!

1

There are 1 best solutions below

4
gidds On BEST ANSWER

I think the issue here is one of variance.

func is a function whose parameter is declared as a Uri.

But your onPickedFunc property would be a function whose parameter can be anything.  You should be able to call it with an Int, or a Uri, or a String, or any other non-null value.

So you can't assign func to it, because that (probably) wouldn't be able to handle an Int or a String or whatever.

In technical terms, the types aren't compatible.  Function parameters have in variance (contravariance); to be a subtype, it must accept a supertype of each parameter.  (This is the reverse of the function's return type, which has out variance AKA covariance.)  So the compiler would flag up a type mismatch.

If you want to store your (Uri) -> Task<Void> function in a property, it would have to be of type (Uri) -> Task<Void> or some supertype, which means the function would have to accept a Uri or some subtype.

(I don't know what type your Uri is, but if it were final, like java.net.URI, then the only subtype would be Uri itself.)


By the way, the kotlin.jvm.functions.Function… interfaces are an implementation detail; the compiler uses them to implement function types on the JVM, but they're not something you should refer to in code (except in special cases such as reflection, I think).