From 7adb38ceaa0f4b7bac2bfec91106313d8d38f4ba Mon Sep 17 00:00:00 2001 From: Joannis Orlandos Date: Thu, 21 Mar 2024 08:32:35 +0100 Subject: [PATCH] Clarify the concept "Local Reasoning" --- .../index.html | 2 +- .../contents.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started-with-structured-concurrency-in-swift/index.html b/docs/getting-started-with-structured-concurrency-in-swift/index.html index e0462a7..ba846c3 100644 --- a/docs/getting-started-with-structured-concurrency-in-swift/index.html +++ b/docs/getting-started-with-structured-concurrency-in-swift/index.html @@ -122,7 +122,7 @@

Structured Concurrency in Swift

Swift 5.5 introduced structured concu cache[url] = image } } -}

The above example is non-trivial. It's not always obvious that you need to lock access to image twice. There are not one, but four traps here.

  1. It's easy to forget to lock access to the cache.
  2. One might lock access to the cache, but omit either the check for an existing image - or the assignment of the image.
  3. When locking access to the cache, one might forget to unlock the lock. When returning a value, as seen in the image(for:) function, the lock should be unlocked after accessing the value, but before returning.
  4. Finally, when locking access to the cache, unlocking could be implemented only after the fetching has completed.

These are all common mistakes, and they're hard to debug and reason about. This is where structured concurrency comes in.

Over the years, many patterns and abstractions have emerged to solve these problems. For example, the Future and Promise pattern is a common way to solve the problem of waiting for a value to be available. These abstractions are not part of the standard library, and are not always easy to work with or reason about. They're also not part of the standard library, leading to a fragmented ecosystem.

Structured Concurrency

Swift has always been focused on safety and maintainability. Common examples are a strong type system, the addition of guard statements, and checks that protect against integer overflows.

Similarly, Structured Concurrency is a language feature that is designed to write concurrent code that is more maintainable and easier to reason about. It's designed to solve these problems, and is the recommended to write concurrent code that is maintainable and easy to reason about.

You're probably familiar with structured programming, as it's a paradigm that every Swift developer uses. By making use of a structured control flow through constructs such as if-statements, for-loops and switch-statements, you're able to write code that is easy to reason about and maintain.

Structured Concurrency is the same concept, but applied to concurrent code. Functions in structured concurrency still have a clear entry and exit point. In Swift, this is done through the use of async functions and the await keyword.

Async Functions

An async function is a function that can pause and resume. Think of it as a function that can be split up into multiple parts.

When you order a pizza, you don't have to wait for the pizza to be made and delivered. You can continue watching your favourite show, while the pizza is delivered to your doorstep. Just like async functions. Should you need to know when the pizza is delivered, you can await the delivery.

func watchTelevision() async throws {
+}

The above example is non-trivial. It's not always obvious that you need to lock access to image twice. There are not one, but four traps here.

  1. It's easy to forget to lock access to the cache.
  2. One might lock access to the cache, but omit either the check for an existing image - or the assignment of the image.
  3. When locking access to the cache, one might forget to unlock the lock. When returning a value, as seen in the image(for:) function, the lock should be unlocked after accessing the value, but before returning.
  4. Finally, when locking access to the cache, unlocking could be implemented only after the fetching has completed.

These are all common mistakes, and they're hard to debug and reason about. This is where structured concurrency comes in.

Over the years, many patterns and abstractions have emerged to solve these problems. For example, the Future and Promise pattern is a common way to solve the problem of waiting for a value to be available. These abstractions are not part of the standard library, and are not always easy to work with or reason about. They're also not part of the standard library, leading to a fragmented ecosystem.

Structured Concurrency

Swift has always been focused on safety and maintainability through local reasoning. Common examples are found in the type system, such as the use of value types. Because Array and Dictionary are value types, you can reason about them locally. You don't need to know about other parts of the code, and how those other parts might be modifying a reference to the same array or dictionary. Because value types are copied when passed around, you can reason about them locally.

Similarly, Structured Concurrency is a language feature that is designed to write concurrent code that is more maintainable and easier to reason about. It's designed to solve these problems, and is the recommended to write concurrent code that is maintainable and easy to reason about.

You're probably familiar with structured programming, as it's a paradigm that every Swift developer uses. By making use of a structured control flow through constructs such as if-statements, for-loops and switch-statements, you're able to write code that is easy to reason about and maintain.

Structured Concurrency is the same concept, but applied to concurrent code. Functions in structured concurrency still have a clear entry and exit point. In Swift, this is done through the use of async functions and the await keyword.

Async Functions

An async function is a function that can pause and resume. Think of it as a function that can be split up into multiple parts.

When you order a pizza, you don't have to wait for the pizza to be made and delivered. You can continue watching your favourite show, while the pizza is delivered to your doorstep. Just like async functions. Should you need to know when the pizza is delivered, you can await the delivery.

func watchTelevision() async throws {
     let store = await PizzaStore.discover()
     let pizza = await store.orderPizza()
     let show = startWatchingTV()
diff --git a/src/contents/posts/2024/03/19-getting-started-with-structured-concurrency-in-swift/contents.md b/src/contents/posts/2024/03/19-getting-started-with-structured-concurrency-in-swift/contents.md
index b0af1ea..47d8f87 100644
--- a/src/contents/posts/2024/03/19-getting-started-with-structured-concurrency-in-swift/contents.md
+++ b/src/contents/posts/2024/03/19-getting-started-with-structured-concurrency-in-swift/contents.md
@@ -107,7 +107,7 @@ Over the years, many patterns and abstractions have emerged to solve these probl
 
 ## Structured Concurrency
 
-Swift has always been focused on safety and maintainability. Common examples are a strong type system, the addition of _guard_ statements, and checks that protect against integer overflows.
+Swift has always been focused on safety and maintainability through _local reasoning_. Common examples are found in the type system, such as the use of value types. Because Array and Dictionary are value types, you can reason about them locally. You don't need to know about other parts of the code, and how those other parts might be modifying a reference to the same array or dictionary. Because value types are copied when passed around, you can reason about them locally.
 
 Similarly, Structured Concurrency is a language feature that is designed to write concurrent code that is more maintainable and easier to reason about. It's designed to solve these problems, and is the recommended to write concurrent code that is maintainable and easy to reason about.