Kotlin / KEEP

Kotlin Evolution and Enhancement Process
Apache License 2.0
3.4k stars 361 forks source link

Provide modern and performant replacement for Enum.values() #283

Open qwwdfsad opened 2 years ago

qwwdfsad commented 2 years ago

This proposal describes a rationale and a path to migrate from function values() provided by each enum type to a collection-based and more predictable abstraction.

Text: https://github.com/Kotlin/KEEP/pull/284/files

Miha-x64 commented 2 years ago

Nice! Why do you propose EnumEntriesList(Supplier) indirection? It's simpler to create a two-in-one implementation of Collections.unmodifiableList(Arrays.asList()) and pass values array directly to its constructor.

qwwdfsad commented 2 years ago

The separate type is useful for potential future additions on a standard library level instead of a language one. E.g. we can potentially extend EnumEntries to have such members as valueOfOrNull, valueOf(ignoreCase=true) and so on.

The main reason to inject supplier is to provide lazy instantiation to be compatible with enums that are being reflectively modified

nikitabobko commented 1 year ago

E.g. we can potentially extend EnumEntries to have such members as valueOfOrNull, valueOf(ignoreCase=true) and so on.

@qwwdfsad I'm still not sure that a separate EnumEntriesList public type makes sense for this purpose. I doubt that we will ever add valueOfOrNull or valueOf(ignoreCase=true) API to EnumEntriesList. Not only it looks ugly SomeEnum.values().valueOfOrNull("Foo"), but it's also easily replaceable with List API: SomeEnum.values().firstOrNull { it.name == "Foo" }

If we will ever want to add valueOfOrNull API then unfortunately it only makes sense as a language feature: SomeEnum.valueOfOrNull("Foo")

Right now because of the EnumEntriesList API we require the OptIn which might lower the feature adoption in the preview

ilya-g commented 1 year ago

@nikitabobko First, it would be SomeEnum.entries.valueOfOrNull("Foo"). Second, it would be more efficient than linear search with firstOrNull.

ZacSweers commented 1 year ago

It appears that a reified enumEntries() function wasn't added to the stlib but was called out as planned in the KEEP here: https://github.com/Kotlin/KEEP/blob/master/proposals/enum-entries.md#collateral-changes. Was this an accidental omission or an intentional change?

The reason I ask is that while most cases can just use Enum.entries, we have a helper function like this that isn't possible without a reified API.

/** Returns an enum entry with the specified name or `null` if no such entry was found. */
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
  return enumValues<T>().find { it.name == name.uppercase(Locale.ENGLISH) }
}
nikitabobko commented 1 year ago

It appears that a reified enumEntries() function wasn't added to the stlib but was called out as planned in the KEEP here

It will appear in Kotlin 1.9.20. The tracking issue for this function in stdlib is: https://youtrack.jetbrains.com/issue/KT-53154