I’m working on a library that I expect to be calle...
# dokka
m
I’m working on a library that I expect to be called from both Kotlin and Swift and would like to improve the usefulness of our reference docs for the Swift developers. Right now the biggest issue is with top level functions. There’s now way for the developers to know what class to prefix those methods with to call from Swift. Something like
UtilsKt.foo()
. My plan was to create a plugin for Dokka to extend the HTML plugin to add another code block section that would show the function declaration in Swift. I’m not sure how to begin. I’m guessing I want to change the ContentModel in some extension point.
Solution I came up with was to create a plugin that provides a
SignatureProvider
and then create additional ContentGroups for function signatures.
i
Hi! Unfortunately, I don't have any experience with swift bindings - could you elaborate on the use case, preferably with examples? It sounds like something quite useful for multiplatform projects in general, and maybe it should be a core functionality of Dokka
Oh, I think I got it. It's probably the same problem as with Java interop, where Java doesn't have top level functions, and Kotlin generates a class so that it can be called. Gotcha We'll think if there's anything we can do about it, thanks for bringing it up. Didn't think it was a problem with swift
m
Swift calls Kotlin code in a very similar way as Java. So if you have a top level function
foo
in a file called
Utils.kt
, Swift will see the function as
UtilsKt.foo
just like Java. There are a few differences between the two. From Swift the property names are required and are part of the signature, but those are already in the documentation. How extension functions work also depends on the type of the receiver. For most extension methods, Swift callers can call them on the object just like Kotlin devs. But there are a few types (primitives, Strings, collections, functions, an Objective-C objects) that they need to fallback and call them the same way that Java would.
Double.foo()
in
Utils.kt
would become
UtilsKt.foo(receiver: Double
. The last difference is that Kotlin native adds
_
to the end of some of the names when building the final framework. This is based on all the code getting merged, so I’m not sure if Dokka would be able to determine when and how many
_
will get added. For my use case, I’m converting a large library that was implementing in Swift and Java to a new Kotlin library. I expect the teams that use it to not be using Kotlin multiplatform, so I need it to still be easy to use for the iOS devs. The java callers have a similar problem, but I’m going with the assumption that they will or can switch to Kotlin. I’m also assuming that the iOS devs will be using Swift and not Objective-C where the names are changed even more.
👍 1
This is what I’ve gotten with my current playing. The
@Swift
isn’t really an annotation, just a way to draw the Swift user eyes to it. I’ve been debating whether I want to repeat all the annotations from the main function declaration.
i
Thanks for the detailed explanation! Hopefully you don't mind if I create an issue for this on GitHub and quote your message
The java callers have a similar problem, but I’m going with the assumption that they will or can switch to Kotlin.
Yeah, it seems to be less of a problem in Java. From personal experience, in migrating codebases Java code is considered to be legacy and no new code is written in it, so there's really no need to call Kotlin code from java, and you can always re-write/convert it to Kotlin if problems arise But with Swift it makes sense in the long run
Neat solution btw! Gets the job done, doesn't look out of place. If you stumble upon any corner cases or problems with it - please let us know, we'd like to consider and avoid it in case we implement something similar 🙂
m
The problem I have now is detecting when I have an extension function on an expect class that is a type alias to a type that doesn’t support extensions functions. Also knowing if a class is an Objective-C class versus a Kotlin class is hard (probably need to go up parent chain looking for something in the platform package to find NSObject), but that won’t find protocols.
i
By the way, since you're done some non-trivial stuff, you might find updated developer guides useful. It a snapshot version for now, but will be released in 1.7.20. Might give you some ideas for where to look as I can't come up with simple solutions for described problems 😞
m
thanks
i
For swift detection, maybe looking at
DClass.sources
would be useful? Not sure what the path is going to look like, but it might end in
.swift
You could, but I wouldn't recommend relying too much on anything related to
DeclarationDescriptor
in your plugin, I'd say it's internal compiler business and you'll have a bad time if/when the compiler changes, there's no guarantees from our end. It'll probably be removed in the future But looking at
path
variable from the base interface might help
m
The class will be imported through a interop klib file, so I’m not sure what the path would show. But I will check it out.