Introducing record pattern for instanceof 2 – Record and record pattern

0 Comments 5:56 AM

In record patterns, it is the compiler’s responsibility to initialize the binding variables such as name and specialty. In order to accomplish this, the compiler calls the accessors of the corresponding components. This means that if you have some extra code in these accessors (for example, return defensive copies, perform validations or apply constraints, and so on) then this code is properly executed.

Let’s go further and work with some nested records.

Nested records and record patterns

Let’s assume that besides the Doctor record, we also have the following record:

public record Resident(String name, Doctor doctor)
  implements Staff {}

Each resident has a coordinator which is a doctor, so a Resident nests a Doctor. This time, we have to nest the record patterns accordingly as in the following code:

public static String cabinet(Staff staff) {  
     
  if (staff instanceof Resident(String rsname,
      Doctor(String drname, String specialty))) {           
    return “Cabinet of ” + specialty + “. Doctor: “
                         + drname + “, Resident: ” + rsname;
  }

}

Both, the resident and the doctor, have a name component. But, we cannot use the binding variable name twice in this context since it will cause a conflict. This is why we have rsname and drname. Notice that the names of the binding variables don’t have to mirror the names of the components. This is possible because the compiler identifies components by position not by their names. But, of course, when is possible, mirroring the name reduces the confusion and keeps a high readability of the code. If there is no need to deconstruct the Doctor record then we can write it like this:

if (staff instanceof Resident(String name, Doctor dr)) {
  return “Cabinet of ” + dr.specialty() + “. Doctor: “
                       + dr.name() + “, Resident: ” + name;
}

Or, if you need a complete deconstruction of components and references to records then write it like this:

if (staff instanceof Resident(String rsname,
  Doctor(String drname, String specialty) dr) rs) {
    return “Cabinet of ” + dr.specialty() + “. Doctor: “
            + dr.name() + “, Resident: ” + rs.name();
}

Adding more nested records follows the same principle. For instance, let’s add the Patient and Appointment records as well:

public record Appointment(LocalDate date, Doctor doctor) {}
public record Patient(
  String name, int npi, Appointment appointment) {}

Now, we can write the following beauty:

public static String reception(Object o) {
  if (o instanceof Patient(var ptname, var npi,
                  Appointment(var date,
                  Doctor (var drname, var specialty)))) {
      
   return “Patient ” + ptname + ” (NPI: ” + npi
          + “) has an appointment at “
          + date + ” to the doctor ” + drname
          + ” (” + specialty + “).”;
  }

}

Notice that this time we have used var instead of explicit types. Feel free to do the same since var fits very well in this case. If you are not familiar with type inference then consider Java Coding Problems, First Edition, Chapter 4, Type Inference which contains detailed explanations and best practices.Of course, using explicit types is also supported. Here we have added binding variables for referencing the records as well:

if (o instanceof Patient(String ptname, int npi,
        Appointment(LocalDate date,
        Doctor (String drname, String specialty) dr) ap) pt) {
      
  return “Patient ” + pt.name() + ” (NPI: ” + pt.npi()
     + “) has an appointment at “
     + ap.date() + ” to the doctor ” + dr.name() + ” (“
     + dr.specialty() + “).”;
}

I think you got the idea!

Leave a Reply

Your email address will not be published. Required fields are marked *