Hey hey, I’m doing something I feel should be much...
# announcements
v
Hey hey, I’m doing something I feel should be much easier than how I’m doing it. I have an abstract class with some basic storage logic for domain entities:
Copy code
abstract class ESGenerics<IDType : DomainID, EntityType : Entity>(
  private val elasticsearchClient: RestHighLevelClient,
  private val objectMapper: ObjectMapper
) {
   // ...
}
All Entity classes has an ID member that should always extend DomainID, so I made this:
Copy code
interface Entity {
  val id: DomainID
}
These functions need EntityType and IDType as types for arguments. Now I feel like I shouldn’t have to pass the IDType to ESGenerics. After all, the EntityType always has an ID field with the correct type. But I can’t figure out how to access the type of EntityType’s ID member in a function declaration. I’d like to rewrite it from:
Copy code
fun getByIDs(ids: List<IDType>): List<EntityType> {
To:
Copy code
fun getByIDs(ids: List<EntityType::id>): List<EntityType> {
How can I do that?
n
I'm a bit confused,
IDType
is a type parameter
v
Yes, I feel like I should be able to go without
n
You think you shouldn't need to pass a type parameter, because you have a runtime value that tells you the type?
v
That’s what I’m hoping to achieve
n
that seems impossible.
types are needed at compile time. values are only known at runtime.
I mean you can do it if you make
ESGenerics
no longer generic on
IDType
, and only use
DomainId
. is that what you're planning?
v
I feel like I should be able to infer it to always be an extension of DomainID at compile time, though
The point is that different domain objects have different ID types
n
Sure, but Kotlin doesn't know how to get that value at compile time.
v
Hmm
n
It might help if you had a complete example of what you hope to happen, including how you want to construct
ESGenerics
v
Sure, one moment
Untitled
I know in Typescript, for example, I could just do
EntityType["id"]
n
I'm not sure how typescript works exactly
but a) the typing is optional, since it's based on a dynamic language,a nd b) AFAIK TS's type system is more advanced than kotlin's
v
I assumed the opposite of B to the true 😮
For no reason in particular
n
why? Kotlin's type system is not particularly advanced
python's static type system is more advanced overall than Kotlin's as well 🙂
v
Heh
Ok
Good to know
I guess I’ll have to live with this very minor inconvenience
Thank you!
n
I suspect what youwant isn't possible, but I have a better understanding now
Hmm the problem is a bit different from what I thought, but I still think it's not possible. Basically, with constrained generics, you can only use whatever the constraint provides
v
Right, and not their members
At least not in method signatures
n
well, you can use the members of
EntityType
, but you can only use the static types up to the guarantees of the constraint. In this case, the constraint is
Entity
, so you'd have to use the base type,
DomainID
v
That’d be fine, though
But I can’t seem to get DomainID from Entity either
n
then just write
fun getByIDs(ids: List<DomainId>)
but, as you can probably see, that loses type safety
v
Right
n
The point is that you cannot access more specialized characteristics of the generic type, in the type system
EntityType
can only be used (at compile time) as an
Entity
, and
Entity
onlyknows
DomainId
, nothing more
The only thing you could do is make the
Entity
interface itself generic
v
I’d still not be able to access it’s (generic) member, though
n
Copy code
interface Entity<IDType : DomainID> {
    val id: IDType
}
Well, in this case, you would be able to, because you'd have to have the generic type, becauser you would have to feed it to entity
but obviously that means that
ESGenerics
is still generic over
IDType
v
The main problem would still be this in a function definition:
Copy code
fun getByIDs(ids: List<EntityType::/*what do I do here*/>)
That’d lose safety if I used DomainID
n
Yes, I agree, but as I said, you'd still need to be generic on IDType
v
Yeah
I guess it just can’t be done 🤷
n
This feature i believe is called "associated types"
v
Is there an RFC or something?
n
So in C++ for example, which has totally unconstrained generics, you can just access nested typedefs/typealiases of the types you are generic on. If they don't exist, it causes a compiler error at the use site.
Other languages support associated types as a constraint
I don't know of one. keep in mind, kotlin is bound by Java style type erasure, I'm not sure but that may play a role here.
Java generics (and therefore, Kotlin generics) are pretty bizarre compared to most generics systems
v
I don’t know enough java to judge that so I’ll take your word on it
n
Like, in Kotlin you might notice how you do
Map.Entry<K, V>
this is extremely weird
In most other languages, we'd say,
Map
isn't a type at all
So you can't access the member types of this non type
instead,
Map
is something that takes two types, and gives you a new type.
So you'd write
Map<K, V>.Entry
Entry doesn't need to be re-parametrized because every Map has its own entry with the correct type arguments.
v
Right yeah I see what you mean
Sidenote do you know if Kotlin RFCs are public?
n
prettys ure they are, and they are called keeps
v
Ah ok
n
v
Yeah found it
I’ll see if there’s anything related, who knows
Thanks a bunch 🙂
n
sure, np