3
votes

I have two shapeless extensible records, person and employee. The employee record is a subtype of person in some sense because it has all of the fields that person does and those fields are all subtypes of the corresponding fields in person:

import shapeless._ ; import syntax.singleton._ ; import record._

val employeeId = ("first name" ->> "Jane") :: ("last name" ->> "Doe") :: ("title" ->> "software engineer") :: HNil

val employee =
      ("id" ->> employeeId) ::
      ("city" ->> "San Francisco") ::
      ("company" ->> "Generic Inc.") ::
      HNil

val personId = ("first name" ->> "Jane") :: ("last name" ->> "Doe") :: HNil

val person =
      ("id" ->> personId) ::
      ("city" ->> "San Francisco") ::
      HNil

How can I check if one record is a subtype of another? I want to be able to do this both at compile time and at runtime. One use-case I have in mind is that I want to statically verify that a function doesn't remove any fields from a record. So my function could take a person and transform it into an employee but if it dropped the "city" or "id" fields the program should not compile.

I also want to be able to compare the shared components of employee and person. I want to view both objects as just persons and check them for equality. How can I do this?

1

1 Answers

1
votes
  • How can I check if one record is a subtype of another?

You may look at the Extractor type class in this repo. It implements both depth and width subtyping.

https://github.com/eugengarkusha/RecordsDeepMerge

  • I want to be able to do this both at compile time and at runtime

Subtyping relation is witnessed in compile time. Use the Extractor type class(from mentioned repo) to get all fields of super-record from sub-record.

  • I also want to be able to compare the shared components of employee and person. I want to view both objects as just persons and check them for equality. How can I do this?

(using the code from mentioned repo):

 type PersonId = Record.`"first name" ->String, "last name" ->String`.T
 type Person = Record.`"id" -> PersonId, "city" -> String`.T 
 employee1.deepExtract[Person] == employee2.deepExtract[Person]
  • I want to statically verify that a function doesn't remove any fields from a record. So my function could take a person and transform it into an employee but if it dropped the "city" or "id" fields the program should not compile.

no subtype checks are needed in this case:

def personToEmployee(p: Person): Employee = ???

type checker won't let you remove city or id fields