https://kotlinlang.org logo
s

Sylvain Patenaude

12/04/2019, 5:53 PM
Dumb quick question: can we implement an extension method with the
expect
/
actual
pattern? EDIT: Looks like it's doable, but the method I want to split is not an extension method after all. So my question is rather: Can we have only some methods of a class that are prefixed with
expect
or does it have to be the full class at that point? For instance, I would have a class where pretty much all methods would be 'common' except for a few that would need to be implemented natively.
r

russhwolf

12/04/2019, 6:17 PM
An expect class needs to have only expect declarations. Follow/star https://youtrack.jetbrains.com/issue/KT-20427 to change that. There’s a couple strategies you can use as workarounds such as having your expect class extend another class/interface that includes your default/shared implementations, or putting your common implementations in extension functions.
👍🏻 1
d

Dmitri Sh

12/04/2019, 6:19 PM
exactly my question from last night. came across the same problem: ith an expected class in shared, not possible to have any method implementation? All methods must be actualized in platform specific actuals? I have a class (decorator) that can have some of its methods actually implemented in shared - but am forced to duplicate the code in actuals. Is this (no pun intended) "expected"? Seems like a waste.
a

ankushg

12/04/2019, 6:23 PM
@Dmitri Sh Would declaring extension functions on your expected class in your common code help reduce duplication? Edit: looks like Russell beat me to it 😊
😇 1
r

russhwolf

12/04/2019, 6:23 PM
It’s the current state of things but it won’t be that way forever. This sort of rough edge is what comes with being an early adopter to a new technology like this.
s

Sylvain Patenaude

12/04/2019, 6:26 PM
Good point @russhwolf. I will use extension functions as needed. I can't extend another class since I'm using `object`s. My methods are kind of static, more like helper functions.
r

russhwolf

12/04/2019, 6:27 PM
Objects can extend interfaces if that helps, but extension functions work just as well if you don’t need to be able to override.
s

Sylvain Patenaude

12/04/2019, 6:31 PM
I know that objects can extend interfaces, but that would mean that my interface would have some default implementation in this case? While feasible, I think the code will be clearer with extension functions. Interfaces with only default code (without real abstract methods) would look weird to me.
Can we have static methods (or
companion
methods in Kotlin terms) in an
interface
? Basically my pattern would look like this:
Copy code
expect object Helper : HelperCommon { // HelperCommon would either be a class or interface with static methods only
    expect fun function1() // specialized natively
    expect fun function2() // specialized natively
    ...
}
Now from another class, I would like to be able to call the functions in
HelperCommon
through
Helper
like this:
Copy code
val someValue = Helper.functionCommon1(...) // functionCommon1 would be static/companion in HelperCommon
At first I wanted to use extension functions, but they behave like member functions while my functions are meant to be static.
r

russhwolf

12/04/2019, 8:01 PM
You can’t have an
expect companion object
in a non-expect class/interface. But you could have a non-expect
object Helper
and have its methods delegate to
internal expect
functions which then have separate implementations per-platform.
s

Sylvain Patenaude

12/04/2019, 8:04 PM
But the internal expect functions would be at module level instead of object level, right? So I wouldn't be able to call Helper.functionThatIsNativelySpecialized().
r

russhwolf

12/04/2019, 8:05 PM
Well, doesn’t have to be internal, I just figured you might want to limit scope
internal would mean consumers can only interact with it through
Helper
s

Sylvain Patenaude

12/04/2019, 8:06 PM
I may be stubborn, but I'm looking for a workaround for the current Kotlin limitation that we mention above and offer a unified interface to calling clients like this: val someVal1 = Helper.commonFunction() val someVal2 = Helper.specializedFunction() //expect/actual
r

russhwolf

12/04/2019, 8:07 PM
Right I might be losing track of your actual use-case
s

Sylvain Patenaude

12/04/2019, 8:08 PM
So you're saying
internal
would do this? I thought it was just a visibility modifier for the callers in same module.
r

russhwolf

12/04/2019, 8:08 PM
No not quite saying that
s

Sylvain Patenaude

12/04/2019, 8:09 PM
My other option is to have 2 separate objects, like
HelperNative
and
HelperCommon
for instance, but if I can avoid it that would be better.
r

russhwolf

12/04/2019, 8:10 PM
Copy code
object Helper {
    fun commonFunction() {
        // .. common impl
    }
    fun specializedFunction() = specializedFunctionInternal()
}

expect fun specializedFunctionInternal() // Will have separate impl
you can do something like that where you delegate so the caller only needs to talk to one object
You might make
specializedFunctionInternal
have
internal
visibility so people don’t call it directly, but you don’t have to
and you could wrap
specializedFunctionInternal()
in a
HelperNative
object if you want but it’s not necessary
s

Sylvain Patenaude

12/04/2019, 8:13 PM
That would work. The only minor caveat is that clients from the same module/package could still call it directly if they wanted, but it's no big deal.
r

russhwolf

12/04/2019, 8:13 PM
Yeah that’s where you could make it
internal
and have
Helper
live in its own module
s

Sylvain Patenaude

12/04/2019, 8:14 PM
Unless I put the
specializedFunctionInternal()
function
private
? Can you have a
private expect fun function()
?
r

russhwolf

12/04/2019, 8:15 PM
No I think it needs to be
public
or
internal
s

Sylvain Patenaude

12/04/2019, 8:16 PM
Ah ok, I tried. 😉 I miss the good old days when I was using
private virtual
functions in C++. Thank you very much for your help @russhwolf.
👍 1
d

Dmitri Sh

12/04/2019, 10:31 PM
@ankushg not sure how extensions would help me avoid code duplications here, can you clarify? Btw -I was searching the other day for a way to add Parcelable support to a common data class, and came (I think, based on the name) your article on that - and was able to do exactly that, so thanks for that!
@russhwolf sure, I understand I am an early adopter and this sort of thing comes with the price - I was not so much complaining as asking if I misunderstood something
a

ankushg

12/06/2019, 10:59 PM
@Dmitri Sh In some simple cases, you can take an
expect class SpecialClass
and define an extension
fun SpecialClass.doSomething()
in common code. This way, if your implementation of
doSomething
is identical across platforms, you can still define it once in Common code, even though you aren't technically allowed to have it inside your
expect class
declaration. Any yup that was me 😊 Glad it was helpful!
d

Dmitri Sh

12/07/2019, 7:38 PM
interesting, I didn't realize I could do that in common code - previously I defined extensions for working with dates in android and iOS code, maybe I can move that to common. And yes, that article was very helpful!