Has there been any discussion around inline classe...
# language-proposals
j
Has there been any discussion around inline classes and having them conform to a contract similar to enums? For example, it'd be nice to be able to generify over the ability to wrap/unwrap. With enums I can bound a generic on
: Enum<T>
which (combined with
inline
) lets me do
T -> String
and
String -> T
conversion. It would be nice to achieve similar
T -> V
and
V -> T
conversions with an inline type (where
V
is the property type) in a generic way. Right now I'm using a factory where you have to pass
::Foo
and
Foo::property
as arguments which leaves a lot to be desired.
👍 3
k
Out of curiosity, what's the use case? I can't think of much for the enum thing either.
j
serialization
k
Of course! 🤦‍♂️
j
in my case, a database where columns are fixed types (Long, String, Double, byte[]) but you want to use more meaningful types. We normally require you to write a full adapter with to/from methods but for Enums we can do it automatically. It would be nice to do the same for inline classes.
k
I wonder whether "an inline class can only have single property" is a permanent rule or something that is going to be "fixed" when the JVM actually gets value types though.
It's under "Current limitations" in the KEEP.
j
It wouldn't be inline in that case, it would be a value type
o
Well, you can define
Inline<T>
and require users to implement the interface of they want automatic handling. The problem with this is that backing val will have to have same name.
k
Tell me if I'm missing something, but from what I understand the main thing preventing multiple properties is that functions can only have a single return value and constantly allocating temporary objects is too slow. That could then be solved with value types.
j
Yeah I was more thinking the compiler could make the companion implement a common interface with to/from conversion. Or perhaps there could be intrinsic top-level to/from functions and a marker supertype we could use in generic bounds.
o
I don’t think to/from conversions to a backing type are always something that should be allowed. If there is an interface/companion function, you can call it from the normal code.
Also a constructor can be private and instance created from the factory method in companion, or something.
I don’t mean it doesn’t make sense, I mean it needs design 🙂
k
(constructors for inline classes can't be private)
o
Ah, right. Sorry for confusion.
Also not sure it is important limitation, or just something that wasn’t designed yet.
First you disallow it, then you design it, then you win 🙂
k
That's about java interop, you can't force someone calling from Java to go trough the constructor.
o
Okay, I need to stop mumbling and go to bed 🙂
r
I believe Keep 87 may address some of these concerns
Copy code
/** new type **/
inline class Id(val value: String)

/** proof there is an isomorphism between [A] and [B] **/
interface Iso<A, B> {
  fun from(a: A): B
  fun to(b: B): A
}

/** proof [Id] <-> [String] **/
extension class IdStringIso : Iso<String, Id> {
  override fun from(a: String): Id = Id(a)
  override fun to(b: Id): String = b.value
}

/** For All [A] for which there is an isomorphic [B] provide a conversion function **/
fun <A, B> A.convert(with iso: Iso<A, B>): B =
  to<B>()

/** This compiles because finds proof in `IdStringIso` **/
val id : Id = "000".convert()
👍 1
Iso is overly generic and the same can be modeled with a simple
To<A, B>
more constrained interface
The compiler will project the discovered instance that satisfies the type predicate and activate the extension syntax
you can even provide a
component1
override that let's you destructure the conversion for all `A`s such as that:
Copy code
val (value) = id
val (id) = value
j
Having to write
IdStringIso
at all is a loss for me. I already have an interface representing a converter and I'm trying to create a single implementation which can be used for any inline class (like I can do for enums)