Inline classes tedious to use considering Java interop

I’m a big fan of type safety and really like the new inline classes feature in 1.3. Unfortunately it gets really tedious to add them to functions that are used from both Kotlin and Java code. I find myself creating many facades like this:

// for Java
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated(message = "unchecked")
fun givePlayerPoints(playerId: Long, points: Int, type: PointTransactionType, roomId: Long?) =
    givePlayerPoints(PlayerId(playerId), PointChange(points), type, if (roomId == null) null else RoomId(roomId))

// PlayerId, PointChange and RoomId are inline classes
fun givePlayerPoints(playerId: PlayerId, points: PointChange, type: PointTransactionType, roomId: RoomId?): PointTransaction {
    ....

I would imagine that this use case will become pretty common, and would much appreciate a usability improvement for this problem. I suppose a simple annotation in the @JvmXxx category would be in order.

Also, I wouldn’t really mind using the boxed types from Java code, taking a little performance hit, to circumvent this issue, but this is not possible because of the name wrangling introduced in 1.3-M2.

3 Likes

This is the real issue IMO, but I can’t think of a better way than the facade/overload you write. If the names weren’t mangled, the Java callers wouldn’t preserve/know the type safety (i.e. you’d call a Uint w/ an Int). If they always accepted boxed types, then you would lose that performance of inline types (though it happens anyways in some generic cases).

I personally think at this point the cost of requiring you to hand-write Java-visible wrappers is preferred over annotation-based conditional exposure changes (has binary compatibility issues across JARs if you change after deployment too). The question is if it occurs so often (i.e. exposing inline classes to Java-side instantiators) that it deserves special treatment…I’d hope not, and/or I’d encourage no longer making them inline classes as opposed to single-val wrapper classes since you’re losing your benefit at the interop boundary anyways.

1 Like

Not sure I agree with that. Imagine writing a library in Kotlin. If it is used by a kotlin project you would want to have those wrappers as inline classes, also you might want to use inline classes internally.
But you would also need java interop, so I think having an annotation creating the java visible methods is useful.
One way to solve type safety is to make those calls boxing. This way you loose some performance at the point you interact with java but don’t stop interop entirely without having to write boilerplate code. There might be many situations where having a fast interop boundary is not that important but you still want better performing values deeper in the stack.

As another option I could imagine having 2 annotations. One would generate the function using boxing and another allowing java to call a UInt function with int trusting the programmer to pass correct values in order to improve performance. This might be the best way.

1 Like

Yes, at least an annotation for generating boxing versions would be great, because that’s not possible at all right now, is it? There isn’t a syntax to force Kotlin to use boxing, except maybe by abusing generics, but that would all be very nasty.

2 Likes

Or just expose the underlying type in the JVM signatures.

Basically I can’t use inline classes for most of my work because it’d not be usable from Java, which kind of sucks. Without name mangling it would have worked. It’s OK to lose some type safety when calling from Java - that already happens for nullability anyway.

2 Likes

Although I’m inclined to agree with you, and had the same internal reasoning about nullability, there is one crucial difference: the compiler will insert runtime null assertions for code callable from Java. The same is not generally possible for inline classes because, while null is a runtime attribute, there is no runtime distinction between PlayerId(1337) and DollarAmount(1337) at all.

However, it could be argued that Kotlin is just a safer language than Java, and the burden of using Java safely may be placed on the developers who do so.

1 Like

I created an issue to switch the - with an underscore _ in order to make them callable from Java

Please vote

1 Like