Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

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 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. “ ”
  2. @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. “ ”
  3. @miciek - declarative, functional - relationships between values - rigorous

    reasoning - imperative - step-by-step statements - operational reasoning Learning from other paradigms Our Paradigm Other Paradigms
  4. @miciek What is it? vs What does it do? declarative

    vs imperative The tools we use shape our thinking!
  5. @miciek The tools we use shape our thinking What is

    it? An immutable value! What does it do? Eeee… It prints ‘4’.
  6. @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!
  7. @miciek What does it do? List<Integer> xs = Arrays.asList(1, 2,

    3, 4, 5); List<Integer> result = new ArrayList < > (); // empty for (Integer x: xs) { result.add(x * 2); } // now result is a list [2, 4, 6, 8, 10] Java
  8. @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)
  9. @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
  10. @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
  11. @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
  12. @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
  13. @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
  14. @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
  15. @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
  16. @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
  17. @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
  18. @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
  19. @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
  20. @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
  21. @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])
  22. @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/
  23. @miciek Iterator<QuerySolution> 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
  24. @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.
  25. @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.
  26. @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
  27. @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
  28. @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!
  29. @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
  30. @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!
  31. @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
  32. @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
  33. @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
  34. @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
  35. @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