Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Immutability Against The Machine

Immutability Against The Machine

Immutability has taken over the software world. Programmers are using immutable values to make their products more maintainable. They are able to focus on higher-level architectural problems instead of hard-to-debug accidental mutations.

However, the software we write often needs to run on a real machine. It needs state, it needs to do many things at once using multiple threads, and it needs to acquire some resources like sockets or files. Moreover, it needs to clean after itself in any condition, even when things go awry, making sure it never leaks memory or resources. We may be tempted to say that solving these concerns requires some old-school mutations. But it doesn’t!

In this talk we will show a real-world application that uses state, multiple threads, and resources. We will use real data from an external Wikidata service, make sure we conform to the API limits, implement a cache, and make sure we release all unneeded connections along the way. Most importantly, all this is going to be modeled as immutable values!

Michał Płachta

November 08, 2023
Tweet

More Decks by Michał Płachta

Other Decks in Programming

Transcript

  1. @miciek
    Michał Płachta
    www.michalplachta.com
    IMMUTABILITY


    AGAINST


    THE MACHINE

    View full-size slide

  2. @miciek
    Back to 2001

    View full-size slide

  3. @miciek
    2001
    Let’s replace
    Haskell with
    Java
    University of


    Texas

    View full-size slide

  4. @miciek
    2001
    Let’s replace
    Haskell with
    Java
    University of


    Texas

    View full-size slide

  5. @miciek
    Dijkstra writes to University of Texas
    https://www.cs.utexas.edu/users/EWD/transcriptions/OtherDocs/Haskell.html
    Facing students with
    the novelty of
    functional programming
    immediately drives
    home the message
    that there is more to
    programming than they
    thought.


    View full-size slide

  6. @miciek
    Dijkstra writes to University of Texas
    https://www.cs.utexas.edu/users/EWD/transcriptions/OtherDocs/Haskell.html
    Facing students with
    the novelty of
    functional programming
    immediately drives
    home the message
    that there is more to
    programming than they
    thought.


    View full-size slide

  7. @miciek
    - declarative, functional


    - relationships between values


    - rigorous reasoning
    - imperative


    - step-by-step statements


    - operational reasoning
    Learning from other paradigms
    Our Paradigm
    Other Paradigms

    View full-size slide

  8. @miciek
    DEMO: printing stuff in the REPL

    View full-size slide

  9. @miciek
    What is it? vs What does it do?
    declarative vs imperative
    The tools we use shape our thinking!

    View full-size slide

  10. @miciek
    The tools we use shape our thinking
    What is it?


    An immutable value!
    What does it do?


    Eeee… It prints ‘4’.

    View full-size slide

  11. @miciek
    - declarative, functional


    - relationships between values


    - rigorous reasoning
    - imperative


    - step-by-step statements


    - operational reasoning
    Learning from other paradigms
    What Does It Do?
    What is It?
    We can learn a lot from there!

    View full-size slide

  12. @miciek
    What does it do?
    List xs = Arrays.asList(1, 2, 3, 4, 5);

    List result = new ArrayList
    < >
    ();
    //
    empty

    for (Integer x: xs) {

    result.add(x * 2);

    }

    //
    now result is a list [2, 4, 6, 8, 10]

    Java

    View full-size slide

  13. @miciek
    What is it?
    val numbers = List(1, 2, 3, 4, 5)

    val doubles = numbers.map(i
    =>
    i * 2)
    / /
    List(2, 4, 6, 8, 10)

    View full-size slide

  14. @miciek
    What is it?
    val numbers = List(1, 2, 3, 4, 5)

    val doubles = numbers.map(i
    =>
    i * 2)
    / /
    List(2, 4, 6, 8, 10)

    Scala
    numbers
    List[Int]
    doubles
    List[Int]
    .map

    View full-size slide

  15. @miciek
    What does it do?
    String tvShow = "The Wire (2002-2008)";

    int extractYearStart(String show) throws Exception {…}

    int extractYearEnd(String show) throws Exception {…}

    int start = extractYearStart(tvShow);
    / /
    2002

    int end = extractYearEnd(tvShow);
    //
    2008

    Java

    View full-size slide

  16. @miciek
    What does it do?
    String tvShow = "The Wire (2002-2008)";

    int extractYearStart(String show) throws Exception {…}

    int extractYearEnd(String show) throws Exception {…}

    int start = extractYearStart(tvShow);
    / /
    2002

    int end = extractYearEnd(tvShow);
    //
    2008

    extractYearStart("Chernobyl (2019)");
    / /
    ???

    Java

    View full-size slide

  17. @miciek
    What does it do?
    String tvShow = "The Wire (2002-2008)";

    int extractYearStart(String show) throws Exception {…}

    int extractYearEnd(String show) throws Exception {…}

    int start = extractYearStart(tvShow);
    / /
    2002

    int end = extractYearEnd(tvShow);
    //
    2008

    extractYearStart("Chernobyl (2019)");
    / /
    ???

    Java

    View full-size slide

  18. @miciek
    What does it do?
    int extractYearStart(String show) throws Exception {…}

    int extractYearEnd(String show) throws Exception {…}

    int extractSingleYear(String show) throws Exception {…}

    Integer year = null;

    try {

    year = extractYearStart(tvShow);

    } catch(Exception e) {

    year = extractSingleYear(tvShow);

    }

    Java

    View full-size slide

  19. @miciek
    What is it?
    def extractYearStart(show: String): Option[Int] = ???

    def extractYearEnd(show: String): Option[Int] = ???

    def extractSingleYear(show: String): Option[Int] = ???
    Scala
    None
    Option[A]
    Some[A]
    val value: A

    View full-size slide

  20. @miciek
    What is it?
    def extractYearStart(show: String): Option[Int] = ???

    def extractYearEnd(show: String): Option[Int] = ???

    def extractSingleYear(show: String): Option[Int] = ???

    val year = extractYearStart(tvShow).orElse(extractSingleYear(tvShow))
    Scala
    extractYearStart
    Option[Int]
    extractSingleYear
    Option[Int]
    year
    Option[Int]
    .orElse

    View full-size slide

  21. @miciek
    - declarative, functional


    - relationships between values


    - rigorous reasoning


    - what is it?
    - imperative


    - step-by-step statements


    - operational reasoning


    - what does it do?
    We don’t have to think like a machine
    The Machine
    Immutability

    View full-size slide

  22. @miciek
    Shaping our thinking habits
    It is not only
    the violin that
    shapes the
    violinist, we are
    all shaped by
    the tools we
    train ourselves
    to use…


    https://www.cs.utexas.edu/users/EWD/transcriptions/OtherDocs/Haskell.html

    View full-size slide

  23. @miciek
    Plus… FP ideas aren’t going away
    https://www.infoq.com/articles/data-oriented-programming-java/

    View full-size slide

  24. @miciek
    Passing immutable values around
    numbers
    List[Int]
    extractYearStart
    Option[Int]
    extractSingleYear
    Option[Int]
    doubles
    List[Int]
    year
    Option[Int]
    .map
    .orElse

    View full-size slide

  25. @miciek
    What about talking to the outside world?

    View full-size slide

  26. @miciek
    IMMUTABILITY AGAINST THE MACHINE
    Using S
    tri
    n
    g
    s, L
    i
    s
    t
    s, Op
    ti
    ons
    Talking to the outside world
    Threads, resource safety, and state

    View full-size slide

  27. @miciek
    -User can search for an attraction name


    -The app finds the attraction and its location


    -It returns movies that are set in this location
    A peculiar travel guide

    View full-size slide

  28. @miciek
    A peculiar travel guide
    > “Bridge of Sighs”
    You searched for “Bridge of
    Sighs”, which is located in Venice.
    Before visiting, you can watch:
    Casino Royale

    View full-size slide

  29. @miciek
    The model
    case class LocationId(value: String)

    case class Location(id: LocationId, name: String)

    case class Attraction(name: String, location: Location)

    case class Movie(name: String, boxOffice: Long)

    case class TravelGuide(attraction: Attraction, movies: List[Movie])

    View full-size slide

  30. @miciek
    We will use Wikidata
    https://query.wikidata.org/


    View full-size slide

  31. @miciek
    Thinking Like A Machine
    https://jena.apache.org/

    View full-size slide

  32. @miciek
    String query = "SELECT DISTINCT ?attraction ?attractionLabel \n" +

    " ?location ?locationLabel WHERE {\n" +

    " ?attraction wdt:P31 wd:Q570116;\n" +

    " rdfs:label ?attractionLabel;\n" +

    " wdt:P131 ?location.\n" +

    "} LIMIT 3";

    RDFConnection connection = RDFConnectionRemote.create()

    .destination("https:
    //
    query.wikidata.org/")

    .queryEndpoint("sparql")

    .build();

    QueryExecution execution = connection.query(QueryFactory.create(query));

    Java
    Thinking Like A Machine
    https://jena.apache.org/

    View full-size slide

  33. @miciek
    Iterator solutions = execution.execSelect();

    while(solutions.hasNext()) {

    QuerySolution solution = solutions.next();

    String id = solution.getResource("attraction").getLocalName();

    String label = solution.getLiteral("label").getString();

    System.out.printf("Got attraction %s (id = %s)%n", label, id);

    }

    Java
    Thinking Like A Machine
    Got attraction Yellowstone National Park (id = Q351)

    Got attraction Eiffel Tower (id = Q243)

    Got attraction Table Mountain (id = Q213360)
    Output

    View full-size slide

  34. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = { … }

    Scala
    Immutability
    https://typelevel.org/cats-effect/

    View full-size slide

  35. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = { … }

    Scala
    Immutability
    https://typelevel.org/cats-effect/
    IO[List[QuerySolution]]
    Immutable value representing a
    potentially side-effectful program that,
    once executed successfully, will produce
    a list of query solutions.

    View full-size slide

  36. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    Scala
    Immutability
    IO.delay( … )
    Creates an immutable value
    representing a potentially side-effectful
    program that will execute the given
    block of code and return the result.

    View full-size slide

  37. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    println(solutionsProgram)

    Scala
    Immutability

    View full-size slide

  38. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    println(solutionsProgram)
    //
    IO(
    .. .
    )

    Scala
    Immutability

    View full-size slide

  39. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    val attractionsProgram: IO[List[Attraction]] =

    Scala
    Immutability
    We don’t have to run anything,


    let’s work with values first!

    View full-size slide

  40. @miciek
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    def parseAttraction(s: QuerySolution): Option[Attraction] = { … }

    val attractionsProgram: IO[List[Attraction]] =

    solutionsProgram.map(solutions
    = >
    solutions.flatMap(parseAttraction))
    Scala
    Immutability

    View full-size slide

  41. @miciek
    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    val attractionsProgram: IO[List[Attraction]] =

    solutionsProgram.map(solutions
    = >
    solutions.flatMap(parseAttraction))
    Scala
    Immutability
    List[QuerySolution]
    =>
    List[Attraction]

    We transformed results without having them!

    View full-size slide

  42. @miciek
    Immutability
    def execQuery(query: String): IO[List[QuerySolution]] = {

    IO.delay(connection.query(QueryFactory.create(query)).execSelect())

    }

    val solutionsProgram: IO[List[QuerySolution]] = execQuery(query)

    def parseAttraction(s: QuerySolution): Option[Attraction] = { … }

    val attractionsProgram: IO[List[Attraction]] =

    solutionsProgram.map(solutions
    = >
    solutions.flatMap(parseAttraction))
    Scala
    solutionsProgram
    IO[List[QuerySolution]]
    attractionsProgram
    IO[List[Attraction]]
    .map

    View full-size slide

  43. @miciek
    DEMO: Let’s code the travel guide!
    > “Bridge of Sighs”
    You searched for “Bridge of
    Sighs”, which is located in Venice.
    Before visiting, you can watch:
    Casino Royale

    View full-size slide

  44. @miciek
    IMMUTABILITY AGAINST THE MACHINE
    Using S
    tri
    n
    g
    s, L
    i
    s
    t
    s, Op
    ti
    ons
    Talking to the outside world
    Threads, resource safety, and state

    View full-size slide

  45. @miciek
    IMMUTABILITY AGAINST THE MACHINE
    IO
    List
    Option
    String
    Ref
    Resource

    View full-size slide

  46. @miciek
    - declarative, functional


    - relationships between values


    - rigorous reasoning


    - what is it?
    - imperative


    - step-by-step statements


    - operational reasoning


    - what does it do?
    We don’t have to think like a machine
    The Machine
    Immutability

    View full-size slide

  47. @miciek
    Shaping our thinking habits
    It is not only
    the violin that
    shapes the
    violinist, we are
    all shaped by the
    tools we train
    ourselves to
    use…


    https://www.cs.utexas.edu/users/EWD/transcriptions/OtherDocs/Haskell.html

    View full-size slide

  48. @miciek
    Let’s go back to 2023

    View full-size slide

  49. @miciek
    Java (will) have it, too!
    FP
    Future


    Java

    View full-size slide

  50. @miciek
    https://www.manning.com/plachta


    40% off code:


    watchplachta40
    www.michalplachta.com

    View full-size slide

  51. @miciek
    Michał Płachta
    www.michalplachta.com
    IMMUTABILITY


    AGAINST


    THE MACHINE
    code, links,
    slides,
    book info

    View full-size slide