KEEP icon indicating copy to clipboard operation
KEEP copied to clipboard

Nested (non-capturing) type aliases

Open serras opened this issue 1 year ago • 3 comments

This is an issue to discuss nested (non-capturing) type aliases. The current full text of the proposal can be found here.

Right now type aliases can only be used at the top level. The goal of this document is to propose a design to allow them within other classifiers, in case they do not capture any type parameters of the enclosing declaration.

serras avatar Dec 20 '24 17:12 serras

I personally think this proposal is trivial and nothing to discuss(in design)(I support it, certainly). Btw, sorry for the off-topic, @serras now that you mentioned them and you are in Jetbrains Kotlin team,

Going even further than capture, it is a non-goal of this KEEP to provide abstraction capabilities over type aliases, like abstract type members in Scala or associated type synonyms in Haskell. Roughly speaking, this would entail declaring a type alias without its right-hand side in an interface or abstract class, and "overriding" it in an implementing class.

interface Collection {
   typealias Element
}

interface List<T>: Collection {
   typealias Element = T
}

interface IntArray: Collection {
   typealias Element = Int
}

Will kotlin support these language features(i.e. capturing type alias, abstract type members, associated type synonyms, or let's say further, dependent functions) in future?

revonateB0T avatar Dec 21 '24 13:12 revonateB0T

Will kotlin support these language features?

I cannot say for sure, although I highly doubt that anything resembling type-level computation would make it into the language. The only exception is many capturing type aliases (you can even see that the first iterations of the proposal in the Git history had those), but there are interesting questions like how would instantiation work for things like:

class Example<T> {
  inner typealias A = List<T>
}

Should one require an instance of A to call the List constructor? How does it relate to things like listOf? Because of those questions we've decided to go first with the obviously useful feature (non-capturing type aliases) and then move to capturing type aliases if needed.

serras avatar Dec 23 '24 15:12 serras

This feature will appear as experimental in Kotlin 2.2.0. This PR will remain open for discussion for some time after the initial release, to gather any feedback.

serras avatar Apr 07 '25 14:04 serras

I understand why nested type aliases are not allowed to capture type parameters. However, why can't local type aliases capture them? A local type alias can't really "escape" in such a way as to leak its parameter (outside of some strange compiler bugs). Like I don't see how this can be problematic:

fun <T> foo() {
  typealias ListT = List<T>
  ...
}

kyay10 avatar Oct 31 '25 02:10 kyay10

There are two main reasons for not allowing them (yet):

  1. Whatever the design, it should be uniform with nested type aliases. We don't want to end in a situation in which you may need a modifier to capture on nested aliases, but not on local ones.
  2. Even thought local type aliases seem "easier", there are some things that may happen in local contexts that may not happen in declaration contexts. For example, you may define an object that captures a value from outside (does it count as capturing?), or you may define an anonymous type (from an object). If we alias them, how should we proceed?

serras avatar Nov 03 '25 10:11 serras

Since this feature is already released (nested type aliases are stable in 2.3.0, local ones are experimental), this KEEP discussion is being closed.

serras avatar Nov 05 '25 09:11 serras