When working with shapeless you'll often find yourself referring to the names of fields using Symbol literals. Shapeless does this by implicitly converting a Symbol to an internal type, called Witness, which has a refinement that specifies the Singleton type of the Symbol literal.
For example, let's say we had a case class Person with the following definition:
case class Person(name:String, occupation:Option[String])
Then we could refer to the fields, assuming we projected our Person class into shapeless using LabelledGeneric, as 'name and 'occupation, respectively. For example, maybe we have a function named swizzle that does something interesting, but requires the field to be an Option:
swizzle[Person]('occupation)
This mechanism is extremely handy and typesafe. For example, if you refer to a field 'foo in the context of a Person, then the code will fail to compile. Alternatively, if Person changes "name" to "fullName", then any code referencing 'name will now fail to compile signaling that code needs to be updated.
While handy, this mechanism is actually too powerful for the problem at hand, and I think the community would benefit if we had access to one that was more targetted. *Please keep in mind: I'm not proposing that shapeless or this mechanism be dropped, only that we get access to second more limited piece of functionality.*
The core issue is that 'foo can refer to any field named "foo" in any case class, when in the examples above, what I really needed was some way to specifically refer to fields within some specific class.
The most appropriate mechanism I can think of for doing this would be to extend case classes so that they have type members with names identical to the fields of the case class. Thus Person would become:
case class Person(name:String, occupation:Option[String]) {
// Inserted by the compiler...
type name = ...
type occupation = ...
}
Going back to our swizzle function, then we might write:
swizzle[Person#occupation]()
The field reference is now entirely contained within the type signature.
The major benefit this addition would have is that IDEs and other tools would now have a direct link to where in your codebase fields are being referenced "by name", and these symbols can now be linked back to their declarations by the IDE. This also means that refactoring is now safe, so that when you rename "name" to "fullName" your refactoring tools can find and update Person#name to Person#fullName with relative ease. While this might be possible with shapeless, it's ad-hoc.
As to the actual type of each field, they should presumably be some kind of singleton type, whose inhabitant is both instantiable and includes a Lens. Ideally, the types would be constructed so that, for example, swizzle could be written such that it would only accept references to fields in the Person case class, or references to fields of a certain type T, but in any case class, or some combination of these constraints.
I'm looking forward to hearing what folks have to say!