Deep Dive Into Pattern Matching & Destructuring

Deep Dive Into Pattern Matching & Destructuring

Pattern Matching and Destructuring are two simple, yet powerful features in functional programming languages. There are several ways we can leverage them to make cleaner code. It also encourages you to think data as a first-class citizen and provide the essential tooling.

In this session, we are going to learn what these techniques bring to the table by looking at some real-world use-cases in Kotlin & Clojure.

C6dbbb399f7658917f60bd1e2a2663ed?s=128

Tamizhvendan S

November 14, 2019
Tweet

Transcript

  1. Lead Consultant www.ajira.tech Tamizhvendan S Passionate, Pragmatic and Polyglot Programmer

    https://www.demystifyfp.com tamizhvendan Deep Dive Into Pattern Matching And Destructuring
  2. Pattern Matching And Destructuring It’s not new!

  3. val texts = arrayOf( "The flight arrived at 12734722.", "The

    meeting starts at 20730700." ) texts.forEach { printTimestamp(it) } Hour: 12, Minute: 34, Second: 22 Hour: 20, Minute: 30, Second: 00
  4. fun printTimestamp(text : String) { val atIndex = text.indexOf("at") val

    timestamp = text .subSequence(atIndex + 3, atIndex + 11) .split(':') val hour = timestamp[0] val minute = timestamp[1] val second = timestamp[2] println("Hour: $hour, Minute: $minute, Second: $second") } A Naive Approach
  5. A Naive Approach fun printTimestamp(text : String) { val atIndex

    = text.indexOf("at") val timestamp = text .subSequence(atIndex + 3, atIndex + 11) .split(':') val hour = timestamp[0] val minute = timestamp[1] val second = timestamp[2] println("Hour: $hour, Minute: $minute, Second: $second") }
  6. Regex to the Rescue fun printTimestamp(text : String) { val

    pattern = "(\\d\\d)7(\\d\\d)7(\\d\\d)" val regex = pattern.toRegex() val timestamp = regex.find(text)UUVgroupValues val hour = timestamp[1] val minute = timestamp[2] val second = timestamp[3] println("Hour: $hour, Minute: $minute, Second: $second") }
  7. Pattern Made The Difference fun printTimestamp(text : String) { val

    pattern = "(\\d\\d)7(\\d\\d)7(\\d\\d)" val regex = pattern.toRegex() val timestamp = regex.find(text)UUVgroupValues val hour = timestamp[1] val minute = timestamp[2] val second = timestamp[3] println("Hour: $hour, Minute: $minute, Second: $second") }
  8. Pattern Matching And Destructuring is not limited to “string” alone

  9. Pattern Matching And Destructuring can be applied to “data”

  10. Representing Data

  11. Primitives & Collections 42, 3.14, "Lorum Ipsum", true

  12. Primitives & Collections 42, 3.14, "Lorum Ipsum", true [0, 1,

    42]
  13. Primitives & Collections 42, 3.14, "Lorum Ipsum", true [0, 1,

    42] {"firstName" : "John", "lastName" : "Doe"}
  14. Representing Data Using Primitives val timestamp = arrayOf(12, 34, 22)

  15. Representing Data Using Primitives val timestamp = arrayOf(12, 34, 22)

    hour
  16. Representing Data Using Primitives val timestamp = arrayOf(12, 34, 22)

    hour minute
  17. Representing Data Using Primitives val timestamp = arrayOf(12, 34, 22)

    hour minute second
  18. Representing Data Using Objects import java.time.LocalTime; class Program { public

    static void main(String[] args) { LocalTime timestamp = LocalTime.of(12, 34, 22); int hour = timestamp.getHour(); int minute = timestamp.getMinute(); int second = timestamp.getSecond(); System.out.println(timestamp); } }
  19. Guess the output import java.time.LocalTime; class Program { public static

    void main(String[] args) { LocalTime t1 = LocalTime.of(12, 34, 22); LocalTime t2 = LocalTime.of(12, 34, 22); System.out.println(t1.equals(t2)); } }
  20. It’s true! package java.time; U` UUa public final class LocalTime

    { U` UUa @Override public boolean equals(Object obj) { if (this Uc obj) { return true; } if (obj instanceof LocalTime) { LocalTime other = (LocalTime) obj; return hour Uc other.hour Ud minute Uc other.minute Ud second Uc other.second Ud nano Uc other.nano; } return false; } }
  21. Value Object An object that represents a descriptive aspect of

    the domain with no conceptual identity is called a Value Object. Value Object are instantiated to represent elements of the design that we care about only for what they are, not who or which they are.
  22. Data Class in Kotlin

  23. Representing Data in Kotlin data class LocalTime(val hour: Byte, val

    minute: Byte, val second: Byte)
  24. Representing Data in Kotlin data class LocalTime(val hour: Byte, val

    minute: Byte, val second: Byte) val t1 = LocalTime(12, 34, 22) val t2 = LocalTime(12, 34, 22) println(t1 Uc t2) U` prints true
  25. Representing Data in Clojure

  26. Representing Data in Clojure

  27. Data More than name-value pairs!

  28. A Login API Response

  29. A Login API Response Login Success

  30. A Login API Response Login Success First-time Login

  31. A Login API Response Login Success First-time Login Bad Credentials

  32. A Login API Response Login Success First-time Login Bad Credentials

    Login Failure
  33. Representing Login Response

  34. Handling Login Response

  35. Representing Login Response

  36. Representing Login Response

  37. Representing Login Response

  38. Representing Login Response

  39. Representing Login Response

  40. Handling Login Response

  41. Handling Login Response

  42. Decouple handler logic from object

  43. Visitor Pattern In object-oriented programming and software engineering, the visitor

    design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle. - Wikipedia
  44. Handling Login Response - Visitor

  45. Handling Login Response - Visitor

  46. Handling Login Response - Visitor

  47. None
  48. Decouple handler logic from object.

  49. Handling Login Response

  50. Handling Login Response

  51. Representing Login Response sealed class LoginResponse { data class LoginSuccess(val

    jwtToken: String)7 LoginResponse() data class FirsTimeLogin(val sessionId: UUID)7 LoginResponse() data class BadCredentials(val message: String)7 LoginResponse() data class ServerError(val error: String)7 LoginResponse() }
  52. Handling Login Response fun handleLogin(res : LoginResponse) { when(res) {

    is LoginResponse.LoginSuccess Uj println("Redirect to dashboard with token ${res.jwtToken}") is LoginResponse.FirsTimeLogin Uj println("Redirect to changekpassword with session id ${res.sessionId}") is LoginResponse.BadCredentials Uj println("Show bad credentials error ${res.message}") is LoginResponse.ServerError Uj { println("Log error: ${res.error}") println("Show something went wrong") } } }
  53. Pattern Matching - Sub Types fun handleLogin(res : LoginResponse) {

    when(res) { is LoginResponse.LoginSuccess Uj println("Redirect to dashboard with token ${res.jwtToken}") is LoginResponse.FirsTimeLogin Uj println("Redirect to changekpassword with session id ${res.sessionId}") is LoginResponse.BadCredentials Uj println("Show bad credentials error ${res.message}") is LoginResponse.ServerError Uj { println("Log error: ${res.error}") println("Show something went wrong") } } }
  54. fun handleLogin(res : LoginResponse) { when(res) { is LoginResponse.LoginSuccess Uj

    println("Redirect to dashboard with token ${res.jwtToken}") is LoginResponse.FirsTimeLogin Uj println("Redirect to changekpassword with session id ${res.sessionId}") is LoginResponse.BadCredentials Uj println("Show bad credentials error ${res.message}") is LoginResponse.ServerError Uj { println("Log error: ${res.error}") println("Show something went wrong") } } } sealed class LoginResponse { data class LoginSuccess(val jwtToken: String)7 LoginResponse() data class FirsTimeLogin(val sessionId: UUID)7 LoginResponse() data class BadCredentials(val message: String)7 LoginResponse() data class ServerError(val error: String)7 LoginResponse() } V/S
  55. Pattern Matching - Value

  56. Pattern Matching - Guards

  57. Pattern Matching - Vector (x = 10, y = 10)

    (x = 10, y = 20, z = 30)
  58. Pattern Matching - Vector (x = 10, y = 10)

    (x = 10, y = 20, z = 30)
  59. 1 2 3 Pattern Matching - First & Rest

  60. 1 2 3 Pattern Matching - First & Rest

  61. Pattern Matching - Map Rectangle with height 12 & width

    12 Circle with radius 12
  62. Pattern Matching - Map Rectangle with height 12 & width

    12 Circle with radius 12
  63. None
  64. Pattern Matching - Map & Guards

  65. Pattern Matching - Map & Guards

  66. Pattern Matching - Map & Guards

  67. Pattern Matching - Map & Guards

  68. Pattern Matching - Map & Guards

  69. Pattern Matching - Map & Guards

  70. Let’s do some destructuring

  71. None
  72. {:hour 12 :minute 34 :second 22}

  73. {:hour 12 :minute 34 :second 22}

  74. {:hour 12 :minute 34 :second 22} Associative Destructuring

  75. {:hour "12"} Associative Destructuring Hour: 12, Minute: 00, Second: 00

  76. {:hour "12"} Associative Destructuring Hour: 12, Minute: 00, Second: 00

  77. fun printTimestamp(text : String) { val pattern = "(\\d\\d)7(\\d\\d)7(\\d\\d)" val

    regex = pattern.toRegex() val timestamp = regex.find(text)UUVgroupValues val hour = timestamp[1] val minute = timestamp[2] val second = timestamp[3] println("Hour: $hour, Minute: $minute, Second: $second") }
  78. None
  79. Positional Destructuring

  80. Positional Destructuring

  81. Software = Data + Behaviour