I just saw the that expect/actual definitions for ...
# multiplatform
m
I just saw the that expect/actual definitions for classes is being downgraded from beta ( We'll do our best to minimize any changes you will have to make.) to experimental (we may drop it any minute). I personally find this quite unfortunate and I know there are many situations (e.g. porting Android libraries to multiplatform) where using expect/actual classes works a lot better than interfaces and factory patterns. This issue is here : https://youtrack.jetbrains.com/issue/KT-61573 Maybe I'm missing something, but if anyone else has thoughts on this, might be a good idea to put this on the comments on the Youtrack issue.
i
This message from Roman aligns with how I've almost exclusively used expect/actual
Our recent guidelines on mutliplatform projects have been already nudging people to use just expect/actual functions and interfaces. You should try to avoid exect/actual classes as they are not really needed in many case. Still, if you really need them, use them. The reason we keep them experimental is that the design expect/actual is quite complicated. We don't plan to drop expect/actual classes, but as we tweak and refine their design there might be some breaking changes to your code in the future.
There just isn't much reason to use expect/actual classes imo if at all given interfaces are essentially the same thing in that scenario while being quite a bit more flexible.
βž• 1
c
I am personally glad that they are moving in this direction. The existing `actual`/`expect` solution pushes a lot of constraints into a implementors. One of the main ones is that there is only one class per platform. I am personally very against a language imposing design decisions into developers. In practice I have found that interfaces and design patterns can meet the role of
actual
/`expect` while also allowing for more extensibility. I am sure it is a hard decision from the JB team to downgrade this functionality back it to experimental. But shows that at least they are willing to make the hard choices for the long term plans of the KMP project.
βž• 1
e
Honestly
actual
classes or objects are VERY handy. I would not push against them just because I don't like them. More freedom equals more adoption.
πŸ‘ 6
πŸ‘πŸΎ 1
Ktor uses them too btw.
m
Interfaces don't really work when I want to typealias existing implementations e.g. on Android we have RoomDatabase. I want to create a multiplatform port for Room, so I use expect/actual and then I can leave the Android side alone and everything that worked compiles and works as normal.
e
Example for my library. I define `expect object`s for each codec I need in
commonMain
, so each platform is forced to have an implementation. Codecs should be singleton as they are expensive, and they should also be public and referenceable directly for an improved devex
c
On the other side. ultimate freedom does not guarantee correctness or good-quality code. So the JB team, as the language designers and owners, need to balance how how much can be done with the language and what bad uses can also be implemented using them. It's like architectures or design patterns. You can use complete freedom and allow people to implement classes any way they like. But in practice, we have seen how some constraints and restrictions(in the form of design patterns), allows developers to write more correct and scalable software.
m
I am using it in my attempt to create a multiplatform port for Room ( https://www.github.com/UstadMobile/door/ ), it is the basis of paging multiplatform ( https://github.com/cashapp/multiplatform-paging ) and seems to be used extensively in moko resources. Right now the multiplatform library ecosystem is vital. I think this change is going to be a big headache for many multiplatform library maintainers (myself included)
e
Plus yes, I use actual typealiases extensively. Very very powerful.
πŸ‘ 2
m
I agree that there are times when a factory/interface kind of pattern is a better idea. But there are situations where expect/actual classes work much better. I would hope if there is feedback from multiplatform library authors that the JetBrains team will consider
βž• 1
e
I will post my use case for feedback on that issue.
πŸ‘ 1
c
the kotlin stdlib itself uses several expect/actual classes, including
Exception
itself: https://github.com/JetBrains/kotlin/blob/7a7d392b3470b38d42f80c896b7270678d0f95c3/libraries/stdlib/common/src/kotlin/ExceptionsH.kt#L16-L21
Copy code
public expect open class Exception : Throwable {
    constructor()
    constructor(message: String?)
    constructor(message: String?, cause: Throwable?)
    constructor(cause: Throwable?)
}
πŸ‘ 1
e
Oh yeah, the easiest example and I forgot about it. There is no way you can really replace that imo
c
The proposal is just to move actual/expect back to Experimental stage with the goal of addressing some design decisions. I dont think anyone has talked about deprecating or removing actual/expect. I foresee that there will always be a place for this feature, maybe just not the same place as it was designed several years ago.
βœ”οΈ 3
☝️ 1
p
Most of the time, having available two tools (expect/actual classes and interface injection) that basically do the same, create more confusion than what it helps. Expect/actual with classes is a bit more technical, so putting it in experimental kind of warns the user to know more details of it. There are certain use cases for it, "You still can use it, but make sure you know the risk/details" Imo seems like a good move
m
I agree that there are various times when an interface is a better idea, but when it comes to porting existing libraries to Kotlin Multiplatform, expect/actual classes are critical to do this without breaking existing consumers. Maybe I don't have enough imagination, but can anyone outline how to replace expect/actual for the Exception class with an interface pattern?
πŸ‘€ 1
https://youtrack.jetbrains.com/issue/KT-61573 I see the issue is now updated to mark expect/actual classes as "beta" instead of "experimental". I think that's much better and gives me much less of a headache.
βœ… 2
g
Expected and actual classes are recommended in the docs https://kotlinlang.org/docs/multiplatform-connect-to-apis.html and I personally couldn't find a better way to implement some stuff in my app, like timers, they are often platform specific so I don't think there is a workaround to that kind of stuff
s
Somebody from Kotlin team suggest the following in that ticket.
Copy code
Nikita Bobko: An alternative for expect/actual class pair is expect fun + plain interface in the common module
Could someone provide an example of this alternative approach?
p
I believe what he means is having a global factory function that will create a specific platform instance of that common interface. Anything that a class exposes can be exposed in an interface, properties and functions, not sure if I am missing something. Make your code depending on that interface instead of a class, simply.
πŸ‘ 1
188 Views