can anyone help me understand what's going on with...
# random
t
can anyone help me understand what's going on with a
value class
not working as expected. it seems like i'm doing stuff the way the docs say should work, but it's not actually working. (details in thread)
specifically, the delegation described here isn't working https://kotlinlang.org/docs/inline-classes.html#inline-classes-and-delegation
here's my minimal example
the error from the intellij scratch file is
Copy code
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch
my understanding of inline value classes was that they were unwrapped at runtime and automatically had all the methods and properties of the wrapped type. is that wrong?
c
Look at the example from the docs again. The class implements MyInterface by delegation. Your class does not
t
i see. so that only works for interfaces - is there a similar pattern for auto-unwrapping the value to access it?
i mean, i can of course make the parameter not private so it can be accessed, but that seems to kind of defeat the point of an inline class that should just kind of fade into the background except for type enforcement
c
The parameter should be public. It is fine to access it
t
ok
s
In my opinion, the main reason for introducing value classes is for type enforcement.
t
yeah, the
inline
aspect kind of makes it feel like it should just auto-become whatever it's wrapping under the hood, but i get why it doesn't - both from technical and philosophical perspectives
a
They’re unwrapped at compile time where possible or “boxed “ like Java boxing works when they’re needed as a reference (generics is one) . There’s no automatic “here is the methods automatically “aspect of it, you can add methods to the type or just expose the val publicly and call uppercase on its property
s
The
typealias
will essentially be that, but that would remove the type safety aspect from it:
Copy code
typealias UserId = String
typealias ItemId = String

fun getUser(id: UserId) {}
fun getItem(id: ItemId) {}

fun main() {
    val itemId: ItemId = "foo"

    getUser(itemId) // this would still compile
}
Copy code
@JvmInline value class UserId(val value: String)
@JvmInline value class ItemId(val value: String)

fun getUser(id: UserId) {}
fun getItem(id: ItemId) {}

fun main() {
    val itemId: ItemId = "foo"

    getUser(itemId) // this would not compile
}
t
type alias doesn't do the type enforcement an inline class does. i think we are going to go the "add members to the inline class" path
👍 1
the type enforcement allows you to avoid putting things in the wrong place. just because it's all strings under the hood doesn't mean that the data in the strings is interchangeable.
but just because i want to force logical separation in the type system to make sure it's clear that values aren't interchangable doesn't mean i don't want/need to manipulate the underlying value
i'm not looking for it to auto-convert the underlying type to the inline type or vice-versa, but it would be nice that members of the underlying type be available without the underlying value having to be public
but yeah, it's not how it works, it just wasn't super clear from the docs because the docs always show the member as private and then there's the delegation section showing that you can treat it like the other type but the examples aren't clear that it's only valid on interfaces
yeah, i know, but the examples in the docs kind of make it look like you can just use it like the underlying type. i know because it's what someone else on my team thought and asked me about it and then when i glanced at the docs, it looked like that to me. i understand how it actually works now and the docs do say in the text how it works, but that doesn't mean that someone who glances at the examples in the docs will immediately grok the details
and when i say "only valid for interfaces" i know it's about the implementation but you can't do implementation by delegation for anything other than interfaces, which is what i meant