How to pass bounded wildcard type argument in Kotlin?

Hendy Irawan :

The class used (in Java, third party API, not changeable):

public class BookmarkablePageLink<T> extends Link<T> {

    public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)

And now I want to call this from Kotlin:

item.queue(BookmarkablePageLink("link", bookmark.page))

bookmark.page is in Java, and it is: public Class<? extends WebPage> getPage()

None of these work:

item.queue(BookmarkablePageLink("link", bookmark.page))

Error: Not enough information to infer parameter T in constructor Bookmarkable PageLink<T : Any!, C : Page!>(...)

item.queue(BookmarkablePageLink<>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any, *>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any, in WebPage>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any, out WebPage>("link", bookmark.page))

item.queue(BookmarkablePageLink<Any, T : WebPage>("link", bookmark.page))

This would be the "hypothetically correct" way to do this in Javaish-speak (just the intention, but it's not real code), but this isn't supported by Kotlin:

item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))

My best workaround is this, which is ugly, but works:

item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))

Surprisingly in Java this was simply:

item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
Robert Jack Will :

I am creating a answer from all the best comments because those already seem very valuable.

Workaround from the question is already a good start:

BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)

Also fair is @AlexeyRomanov's intermediate variable (or a similar intermediate function):

val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)

Also valuable for all who find this question via Google might be a short summary of Kotlin vs Java handling of type-variance as explained in Kotlin's documentation:

  • in Java the handling is at call-site using wildcards (which you can't use, because call-site is in Kotlin)
  • and in Kotlin the handling is at declaration site using in and out keywords (which you can't use, because your declaration is in Java)

Additionally, Java constructors at call-site only allow to specify type arguments from the class, while in Kotlin the constructor call has two type arguments: one from the class and the other from the constructor. So in Java, we have to say

new BookmarkablePageLink<T>("something", Page.class)

and in Kotlin

BookmarkablePageLink<T, Page>("something", Page::class.java)

despite both calling the same constructor with the same arguments.

Given that Kotlin chose an approach for variant types which is the exact opposite of Java's, I am still happy, that we only need workarounds in so few cases. ;-)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=36374&siteId=1