Certainly a long shot but are there any discussion...
# language-evolution
m
Certainly a long shot but are there any discussions about introducing types that are completely erased (not just generics) in Kotlin? A bit like the typescript type system. At built time, all the type checking would happen. At run time the objects could be some
Map
-like type I guess and property accesses would be cast to the build-time type (and assert if wrong). Does that make any sense?
e
Out of curiosity, what would be the benefit of that?
m
I'm generating models for GraphQL queries and it can become quite complex to the point that it generates a lot of code that takes lots of time to compile and load
And I don't really need runtime information because the objects are "verified" to be of the "expected" shape by the server (and it could also be validated client side if needed too)
Looks like the TS folks have it easier
e
generates a lot of code that takes lots of time to compile
Wouldn't a build time type checker have the same issue? Or does the type checking take a negligible amount of time?
m
Yea I guess compile time would be in the same ballpark I guess. But not having to emit .class files and what not, I'm hoping it can be a bit faster
Currently an issue we have is that class names become so long that they don't fit on the 256 Mac-OS file name limit
Also this generated code goes through kapt and ksp and other things that have to process it. If we skip all of that, I'm hoping to save a bunch on compile time
And runtime is also a thing obviously
c
Maybe generating value classes might help with the runtime issue? That would probably be a pretty big change to the library/code-gen, though. Alternatively, maybe you don’t need to do everything strictly through the GraphQL library? It’s kinda gross, but GraphQL is ultimately just a layer over REST, so you could just send a POST request with the GraphQL query in the body, and the result will just be normal JSON that could be deserialized to
JsonElement
with #serialization (or other similar types from other serialization libs)
m
Maybe generating value classes might help with the runtime issue?
Maybe! Will check this!
send a POST request with the GraphQL query in the body, and the result will just be normal JSON that could be deserialized to
JsonElement
That works of course but the developer experience is nothing similar to having in-IDE autocomplete, inline documentation, deprecations, etc...
c
Yeah, it’s just a fault with GraphQL in general. It’s supposed to be a language-neutral tool, but like most things web-related, really only works well with JS.
m
You can feel it's designed for the web first but the Kotlin experience is really good too. The type system maps nicely and not having to write a serializer and having autocomplete + schema from your API right in your IDE is pretty great
It's only for the edge cases/huge schemas where you can feel the weight of the type system
e
Casey, is your suggestion something like
Copy code
value class Response(private val data: Map<String, Any>) {
    val foo: Foo
        get() = Foo(data["foo"] as Map<String, Any>)
    val optional: String?
        get() = data["optional"] as String?
}
etc.?
unfortunately I don't think it really saves on compile time, because Kotlin still generates boxed classes for every value class
c
Yeah, that’s the basic idea that came to mind when Martin suggested having classes backed by a map-like object
e
Scala does have structural types (that aren't real classes), but the implementation is pretty hairy and I don't think it would fly in Kotlin
m
Thanks for the pointer. 'structural types' sounds exactly like what I was looking for
Mmm without the reflection bits I guess...
e
well, it is better in Scala 3, it can be implemented without reflection https://docs.scala-lang.org/scala3/reference/changed-features/structural-types-spec.html
that would be a bit more likely for Kotlin, but require compiler support
y
You can even do
Copy code
object MapDelegate {
    operator fun <R> getValue(map: Map<String, Any>, prop: KProperty<*>): R = map[prop.name] as R
}
@JvmInline value class Response(private val data: Map<String, Any>): Map<String, Any> by data 

val Response.foo: Foo? by MapDelegate
where MapDelegate can be used as a delegate for any object that is a
Map<String, Any>
. Sadly value classes don't allow doing
by underlyingValue
for some reason, and so I had to define them as extension properties. Only issue is that sadly the name of the property is accessed through the
KProperty
object, which requires an object to exist per property.
e
We plan to do this with the further work on the contracts. The prototype we’ve developed allows declaring types like this:
Copy code
typealias PositiveInt = Int requires { it > 0 }
The additional requirement is completely erased at run-time but is checked at compile-time, so this code will not compile:
Copy code
val x: Int = getSomeInt()
val y: PositiveInt = x // cannot assign PositiveInt to Int
But this code will compile:
Copy code
val x: Int = getSomeInt()
require(x > 0)
val y: PositiveInt = x // OK
You can imagine using it with other types like Strings to represent domain-specific restricted string subsets, maps, etc.
K 1
m
Oooohh interesting 👀 . Is there a KEEP/Youtrack were I can follow progress?
e
KT-51417 Restricted types