Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Why Scala Records with Structural Types and Macros?
Clone this wiki locally
Ideally, record types in Scala would satisfy the following requirements:
- Fields should be named
- Fields should be accessed with a path (e.g.,
- Auto-completion in the IDEs should work
- Records should report actionable error messages
- Least upper bounds (LUBs) of records should not depend on the order of their fields
- Record types should be printed in a comprehensible manner
- Records programs should compile and execute quickly
Design of Scala Records
Scala Records are represented by structural types in which every method is a macro. Structural types are printed nicely, auto-completion works, and they are accessed with a path. Macros in the method implementation take care of specialization and presenting actionable error messages. Although, they satisfy most of the above mentioned requirements, their drawback is that all operations on records are calls to whitebox macros.
Why not shapeless Records?
The first thing that came to mind, with respect to the requirements, were the
shapeless records that are based on
HLists. We evaluated
them and found the following:
In benchmarks, compilation time grows exponentially with the number of fields:
Auto-completion does not work as field information is stored in the types
Types of are not printed nicely: i) they are not printed in an infix position, ii) they are printed with prefixes. Here is an example:
scala> ("name" ->> "Hannah") :: ("age" ->> 30) :: HNil res0: shapeless.::[String with shapeless.labelled.KeyTag[String("name"),String], shapeless.::[Int with shapeless.labelled.KeyTag[String("age"),Int], shapeless.HNil]] = Hannah :: 30 :: HNil
- Least upper bounds of
HMaps do not work because they use an
HListas the underlying type and
HLists impose an ordering of the fields. For example:
scala> :paste List( ("name" ->> "Hannah") :: ("age" ->> 30) :: HNil, ("age" ->> 30) :: ("name" ->> "Hannah") :: HNil ).head.get("name") <console>:32: error: No field String("name") in record shapeless.::[shapeless.labelled.KeyTag[_ >: String("age") with String("name") <: String, _ >: Int with String], shapeless.::[shapeless.labelled.KeyTag[_ >: String("name") with String("age") <: String, _ >: String with Int], shapeless.HNil]] ).head.get("name") ^
Towards a Solution That is Type-Based and Satisfies all the Requirements
We are not very proud of using structural types and macros to achieve our goals. Therefore, we are looking for a solution that would satisfy all the requirements for records, and does not require the use of structural types and macros. Until such solution is found Scala Records should serve their purpose to simplify access to structured data and to flesh-out users' requirements.