<jupyter_start><jupyter_text>Algebraic Data Types and Pattern Matching  Java Version<jupyter_code>System.out.println(Runtime.version());
System.out.println(System.getProperty("java.home"));<jupyter_output><empty_output><jupyter_text>Algebraic Data Types and Where to find them ?![Fantastic Beast](images/fantastic-beasts.jpg)  Algebraic Data TypesComposite type of product types and sum types- product types (A x B x C)- sum type  (A | B | C)  Algebraic Data Types in OCamlExamples of product types and sum types in OCaml```ocaml(* record *)type car = { brand: string; color: string; };;type bus = { brand: string; height: float; };;``````ocaml(* variant *)type vehicle = Car of car | Bus of bus ;;```  Pattern Matching```ocamllet color = function | Car { color=c } -> c | Bus _ -> "yellow" ;;```  Pattern Matching: when clause```ocamllet okayForLowBridge = function | Car _ -> true | Bus { height=h } when h  true | _ -> false ;;```  Equivalence in OOP- sum type  (interface)  ```java  interface Vehicle { }  ```- product types  (class)  ```java  class Bus implements Vehicle {    String name;    double height;  }  ```  Differences FP vs OOP- OOP defines  - open types,  - closed functions (methods)- FP defines  - closed types,  - open functions  OOP == polymorphismActual: OOP | Behaviors      | Function             | Method         || -------------- | -------------------- | -------------- || class POV      | outside a class      | inside a class || Open interface | visitor / instanceof |  polymorphism  | > having open interfaces has a cost !  ![Rick Deckard](images/blade-runner-2049.jpg)  With Pattern matchingProposed: fusion OOP + FP | Behaviors       | Function         | Method         || --------------- | ---------------- | -------------- || Closed type???  | pattern matching |  polymorphism  || Open interface  | pattern matching |  polymorphism  |  Pattern Matching in Java  Plan- expression switch (Java 12 to 14)- record  (Java 14+)- sealed interface (Java 15+)- instanceof enhancement (Java 14+)- future ?  Expression Switch- Enhance switch to be an expression too- Fix C switch warts ?  What wrong with the C switch ?`break` is easy to forget (fallthrough) + weird scope<jupyter_code>void color(String vehicle) {
  switch(vehicle) {
    case "car":
    case "sedan":
      var length = vehicle.length();
      System.out.println((length < 4)? "blue": "red");
      // oops
    case "bus":
      var length = 0;   // oops
      System.out.println("yellow");
      break;
  }  // oops no default
}
color("sedan");<jupyter_output><empty_output><jupyter_text>Arrow Syntax : Enhance existing switch- avoid fallthrough: use curly braces- allow comma separated values<jupyter_code>void color(String vehicle) {
  switch(vehicle) {
    case "car", "sedan" -> {
      var length = vehicle.length();
      System.out.println((length < 4)? "blue": "red");
    }
    case "bus" -> {
      var length = 0;
      System.out.println("yellow");
    }
  } // oops no default
}
color("sedan");<jupyter_output><empty_output><jupyter_text>Expression Switchswitch can be used as an expression, `default` is mandatory !<jupyter_code>String color(String vehicle) {
  return switch(vehicle) {
    case "car", "sedan" -> {
      var length = vehicle.length();
      yield (length < 4)? "blue": "red";
    }
    case "bus" -> "yellow";
    default -> {
      throw new AssertionError();
    }
  };
}
System.out.println(color("sedan"));<jupyter_output><empty_output><jupyter_text>Yield backward compatibility issue`yield` is enable as keyword only at the start of an instruction<jupyter_code>void yield(int value) { }
void color(String vehicle) {
  yield (42);
}<jupyter_output><empty_output><jupyter_text>Future```javaString color(Vehicle vehicle) {  return switch(vehicle) {    case Car(String brand, Color color) -> color;    case Bus(String brand, double height) -> "yellow";  };  //no default}``` We need to be able to deconstruct a class  Record  Example of RecordDeclaration<jupyter_code>record Bus(String brand, double height) { }<jupyter_output><empty_output><jupyter_text>Usage<jupyter_code>var bus = new Bus("imperial", 7);
System.out.println(bus);<jupyter_output><empty_output><jupyter_text>Constructors<jupyter_code>record Bus(String brand, double height) {
  // canonical constructor, generated automatically
  // public Bus(String brand, double height) {
  //   ...
  // }
  // compact constructor
  public Bus {
    Objects.requireNonNull(brand);
  }
}<jupyter_output><empty_output><jupyter_text>equals, hashCode and toStringare automatically generated<jupyter_code>record Bus(String brand, double height) { }
var bus1 = new Bus("imperial", 7);
var bus2 = new Bus("imperial", 7);
System.out.println(bus1.equals(bus2));<jupyter_output><empty_output><jupyter_text>Records are immutableAvoid mutation during the matching```javaString color(Vehicle vehicle) {  return switch(vehicle) {    case Bus(_, double height) when (bus.height = 3)  {}    case Bus(_, double height) when bus.height == 3) -> {}    default -> ...  };}```  Reflection support<jupyter_code>record Bus(String brand, double height) { }
var components = List.of(Bus.class.getRecordComponents());
System.out.println(components);<jupyter_output><empty_output><jupyter_text>Restrictions- shallow immutability- no inheritance- other constructors has to delegate to primary constructor,  initializer blocks are not supported  Sealed interface  Closed hierarchyAdd a keyword `sealed` + a `permits` list```javasealed interface Vehicle  permits Car, Bus { }record Car(String brand, String color) implements Vehicle { }record Bus(String brand, double height) implements Vehicle { }```  Add inference of `permits` clause ?The clause `permits` is inferred if everything in the same compilation unit<jupyter_code>sealed interface Vehicle {
   // inferred permits Car, Bus
  record Car(String brand, String color) implements Vehicle { }
  record Bus(String brand, double height) implements Vehicle { }
}<jupyter_output><empty_output><jupyter_text>ExhaustivenessThe compiler doesn't require the `default` clause anymore.```javaString color(Vehicle vehicle) {  return switch(vehicle) {    case Car car -> car.color;    case Bus bus -> "yellow";  };  //no default}```but before switch on type, let starts by enhancing `instanceof`  Enhanced `instanceof` - Introduce de-construction- Fix the unnecessary cast  What wrong with the old instanceof ?The cast is unnecessary.<jupyter_code>record Bus(String brand, double height) {
  public boolean equals(Object o) {
    if (!(o instanceof Bus)) {
      return false;
    }
    var bus = (Bus) o;   // <-- that cast
    return brand.equals(bus.brand)
        && Double.compare(height, bus.height) == 0;
  }
}<jupyter_output><empty_output><jupyter_text>> The VM routinely removes it, so it's not present> in the generated assembly code  Type test patternDeclare a variable available if the `instanceof` is true<jupyter_code>record Bus(String brand, double height) {
  public boolean equals(Object o) {
    return o instanceof Bus bus
        && brand.equals(bus.brand)
        && Double.compare(height, bus.height) == 0;
  }
}
var bus = new Bus("imperial", 7);
var bus2 = new Bus("imperial", 7);
System.out.println(bus.equals(bus2));<jupyter_output><empty_output><jupyter_text>Type test vs Code block<jupyter_code>record Bus(String brand, double height) {
  public boolean equals(Object o){
    if (o instanceof Bus bus) {
      return brand.equals(bus.brand)
          && Double.compare(height, bus.height) == 0;
    }
    return false;
  }
}<jupyter_output><empty_output><jupyter_text>Type test vs Code block<jupyter_code>record Bus(String brand, double height) {
  public boolean equals(Object o){
    if (!(o instanceof Bus bus)) {
      return false;
    }
    return brand.equals(author.bran)
        && Double.compare(height, bus.height) == 0;
  }
}<jupyter_output><empty_output><jupyter_text>More fun<jupyter_code>public double add(Object o1, Object o2) {
  if (o1 instanceof Integer i1 && o2 instanceof Integer i2) {
    return i1 + i2;
  }
  throw new ArithmeticException();
}<jupyter_output><empty_output><jupyter_text>Even funnier<jupyter_code>public void loop(Object o) {
  while((o instanceof Boolean b) && b) {
    System.out.println(o);
    o = false;
  }
}
loop(true);<jupyter_output><empty_output><jupyter_text>Future ?  Switch on types```javaString brand(Vehicle vehicle) {  return switch(vehicle) {    case Car car -> car.brand;    case Bus bus -> bus.brand;  };  //no default}```  Deconstruction of local declaration  Extracting values of a record<jupyter_code>record Car(String brand, String color) {}
var car = new Car("imperial", "red");
var brand = car.brand();
var color = car.color();
System.out.println(brand + " " + color);<jupyter_output><empty_output><jupyter_text>Use destructuring```javarecord Car(String brand, String color) {}var car = new Car("imperial", "red");Car(String owner, String color) = car;System.out.println(owner + " " + color);```  With inferenceReusing `var` and `_````javarecord Car(String brand, String color) {}var car = new Car("imperial", "red");Car(_, var color) = car;System.out.println(color);```  Tuple ?  Use inferenceRemoving the name of the type which can be inferred too```javarecord Car(String brand, String color) {}Car car = ("imperial", "red");   // inference(_, var color) = car;            // inferenceSystem.out.println(color);```  Inference in for loop (tuple)The type Map.Entry is inferred```javaMap mapNameToCar = ...for((var name, var car) : mapNameToCar.entrySet()) {  System.out.println(name + " " + car);}```  Deconstruction in switch  A switch on types + destructuringAllow to de-construct the content of a record```javaString brand(Vehicle vehicle) {  return switch(vehicle) {    case Car(var brand, _) -> brand;    case Bus(var brand, _) -> brand;  };  //no default}```  Deconstructing instanceof```javarecord Bus(String brand, double height) { public boolean equals(Object o) {   return o instanceof Bus(String brand2, double height2)     && brand.equals(brand2)     && Double.compare(height, height2) == 0; }<jupyter_code>//}
//var bus = new Bus("imperial", 7);
//var bus2 = new Bus("imperial", 7);
//System.out.println(bus.equals(bus2));
//```<jupyter_output><empty_output><jupyter_text>Deconstructing + var```javarecord Bus(String brand, double height) { public boolean equals(Object o) {   return o instanceof Bus(var brand2, var height2)     && brand.equals(brand2)     && Double.compare(height, height2) == 0; }<jupyter_code>//}
//var bus = new Bus("imperial", 7);
//var bus2 = new Bus("imperial", 7);
//System.out.println(bus.equals(bus2));
//```<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13830285982184717, 'fraction_numerical': 0.006000937646507267, 'mean_word_length': 4.177669902912621, 'pattern_counts': {'":': 6, '<': 85, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '509138', 'license': 'MIT', 'n_tokens_mistral': 3325, 'n_tokens_neox': 3192, 'n_words': 977, 'path': 'slideshow/algebraic-data-type-and-pattern-matching.ipynb', 'repo_name': 'KengoTODA/amber-record', 'size': '10665'}