<In case> people didn’t know :slightly_smiling_fac...
# feed
p
In case people didn’t know 🙂 🧵
g
I feel like it's a bit against the "value class" mechanism, that is just about wrapping a known type to adds build-time constraints -> so being more specific. Can I ask your use-case for using generics on value class?
p
g
Thanks! I always felt it was a bad example of value class, compared to a more structured sealed class... like we know there is exactly/always 2 possible cases and methods are related to those cases so shouldn't be always available with default returns... maybe there is a performance reason behind that, I don't understand 🤔
e
yes, it's to avoid an extra allocation in the regular (non-exceptional) path
🙏 1
p
TBF, a combination of sealed interfaces and inline classes can provide something similar that also works with when clauses…
Copy code
sealed interface Result<out T> {
  value class Success<T>(
    val value: T,
  ) : Result<T>
  value class Failure(
    val error: Throwable, // or custom
  ) : Result<Nothing>
}
Kotlin 1.7 will allow for generics on value classes so this kind of pattern will be even more powerful 🙂
👍 1
My personal favourite will be:
Copy code
sealed interface: Lce<out L, out C, out E> {
  value class Loading<L>(val query: L) : Lce<L, Nothing, Nothing>
  value class Content<C>(val content: C) : Lce<Nothing, C, Nothing>
  value class Error<E>(val error: E) : Lce<Nothing, Nothing, E>
}
Although, if we don’t need a query for loading and we are happy with exceptions this is the same as a typealias of
Result<T>?
🙂
e
upcasting a value class to an interface incurs allocation
g
So in this last example, Loading becomes a class instead of a value class? If so is there a lint warning or something?
e
if you pass around a
Loading
value with type
Lce
, then it gets auto-boxed. just like how
Copy code
val x: Int = 1
val y: Number = x
will auto-box
Int
this may not be how it works in the future: https://youtrack.jetbrains.com/issue/KT-27576 but it is true for now
🙏 1
p
Oh, yeah that’s a good point. Forgot about the Auto-boxing 😞 Although that’s only for primitives right? inlined sealed classes will be 🎩 👌 Finally can have headless union types 🤞 If we add multiple params to value classes (i.e. tuples, shame they were removed) I will be a very happy person 🙂
e
value classes act very much like primitives: there is a non-value class generated for each one, which is used to hold it whenever it is used in a position where a value class is not a valid option (e.g. nullable/upcasted/generic types)
e.g.
Copy code
@JvmInline value class Foo(val foo: Any)
val x = Foo("hello")
x as Any == x as Any // true
x as Any === x as Any // false, because of boxing
💯 1
just like how
Copy code
val y = 1000
y as Any == y as Any // true
y as Any === y as Any // false, because of boxing
👍 2