Last active
July 13, 2021 20:01
-
-
Save dcastro/ff2ecdf14acf58d5231fe46590000796 to your computer and use it in GitHub Desktop.
Shapeless - get a field's name in a type-safe way
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shapeless._ | |
import shapeless.ops.record.Keys | |
import shapeless.ops.hlist.Selector | |
import shapeless.tag._ | |
/** | |
* Gets the name of a case class's field, in a type-safe way. | |
* If the class does not have a field with the given name, the program won't compile. | |
* | |
* Kinda similar to C#'s `nameof` operator, but not bolted onto the language | |
* https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/nameof | |
* | |
* @example | |
* | |
* {{{ | |
* > import shapeless.Witness | |
* | |
* > case class C(a: Int) | |
* | |
* > getFieldName[C, Witness.`"a"`.T].get | |
* res0: String = "a" | |
* | |
* > getFieldName[C, Witness.`"b"`.T].get | |
* error: could not find implicit (...) | |
* }}} | |
* | |
* Using Typelevel's scala compiler (https://typelevel.org/scala/) | |
* | |
* {{{ | |
* > getFieldName[C, "a"].get | |
* res0: String = "a" | |
* }}} | |
*/ | |
def getFieldName[A, F]: GetFieldName[A, F] = new GetFieldName | |
class GetFieldName[A, F] { | |
def get[L <: HList, KeyList <: HList](implicit | |
// we need to be able to convert our case class `A` to a labelled hlist `L` | |
ev: LabelledGeneric.Aux[A, L], | |
// we grab the keys of the labelled `L`, into an hlist `KeyList` | |
ev2: Keys.Aux[L, KeyList], | |
// from the key list, we select the first field with a name matching `F` | |
ev3: Selector[KeyList, Symbol with Tagged[F]] | |
): String = { | |
val keys: KeyList = Keys[ev.Repr].apply() | |
keys.select[Symbol with Tagged[F]].name | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment