Video #356: Beyond Basics: Superpowers
Episode: Video #356 Date: Mar 2, 2026 Access: Members Only 🔒 URL: https://www.pointfree.co/episodes/ep356-beyond-basics-superpowers

Description
We show off some superpowers unlocked by embracing isolation, noncopyable, and nonescapable types by showing how they can be used to add incredible safety and performance to a legacy C API, and we will bring everything together to see how these tools make testing an app that uses Composable Architecture 2.0 and SQLiteData like magic.
Video
Cloudflare Stream video ID: 2b46a997d2c550980413583e3cb1eb58 Local file: video_356_beyond-basics-superpowers.mp4 *(download with --video 356)*
References
- Discussions
- the Composable Architecture
- SQLiteData
- SE-0390: Noncopyable structs and enums
- SE-0446: Nonescapable Types
- 0356-beyond-basics-isolation-pt2
- Brandon Williams
- Stephen Celis
- Mastodon
- GitHub
- CC BY-NC-SA 4.0
- source code
- MIT License
Transcript
— 0:05
We have now shown that once isolation is strictly controlled that even time-based asynchrony can be tested in a synchronous fashion with 100% deterministic results.
— 0:14
And we only showed this for immediate clocks, but a similar thing can be shown with test clocks, which are a kind of clock that suspend forever when they sleep and only un-suspend when someone from the outside tells them that some amount of time has passed. Test clocks are great for when you want to test truly test every aspect of how time flows through your features, and helps you wiggle into every little nook and cranny of your code, but there is just a tiny bit of work that needs to be done in Swift before this is possible. We need nonisolated(nonsending) versions of both withUnsafeContinuation and withTaskCancellationHandler . Once that is possible test clocks will be able to squash all unnecessary suspension points and give us the ability to fully test the flow of time without sprinkling yields all throughout our code. Brandon
— 1:00
Let’s move on to the next demo to show off just how amazing isolation, non-copyable types and non-escaping types are. While working on this series we worked on a little demo to get a better understanding of how everything works. That demo provides a safe interface to a popular C library that enforces the rules of the library statically so that the compiler can help prevent us from interacting with the library incorrectly.
— 1:28
The C library in question here is indeed SQLite, something we have talked about a ton on recent episodes, and some might say too much. We promise we are not opening that topic back up right now. What we are discussing here really has nothing to do with SQLite and has everything to do with interacting with global mutable state in a safe, ergonomic and performant manner.
— 1:51
We are not going to be spending a ton of time explaining how SQLite works. We’ve already done that in past episodes. Instead we are going to be using it as a really interesting example to show how in shockingly few lines of code we can enforce correctness when it comes to interacting with a tricky and easy-to-get-wrong C interface.
— 2:09
I will now demo what we were able to accomplish with Swift in just a few days of playing around with Swift’s tools, and then later in this series we will show what it takes to build these tools. Safely interacting with C libraries
— 2:22
I am in an SPM package that has some very rough, early experiments of us exploring how far we can push Swift to force correctness in our interactions with SQLite, and do so in a way that catches problems at compile time instead of runtime, and with as little overhead as possible. And I’ve got a stubbed out test suite open right now: @Suite struct SQLiteIsolationTests { let database: SQLiteDatabase init() async throws { database = try await bootstrapDatabase() } }
— 2:45
The bootstrapDatabase function creates a connection to a database and executes some queries to create a few tables and insert a few values into those tables: private func bootstrapDatabase() async throws -> SQLiteDatabase { let database = try SQLiteDatabase( path: "\(NSTemporaryDirectory())\(UUID().uuidString).sqlite" ) try await database.write { db in try db.execute( """ CREATE TABLE "remindersLists" ( "id" INTEGER PRIMARY KEY, "title" TEXT NOT NULL ) STRICT """ ) try db.execute( """ CREATE TABLE "reminders" ( "id" INTEGER PRIMARY KEY, "title" TEXT NOT NULL, "remindersListID" INTEGER REFERENCES "remindersLists"("id") ON DELETE CASCADE ) STRICT """ ) try db.execute( """ INSERT INTO "remindersLists" (title) VALUES ('Personal') """ ) try db.execute( """ INSERT INTO "remindersLists" (title) VALUES ('Business') """ ) try db.execute( """ INSERT INTO "reminders" (title, "remindersListID") VALUES ('Get milk', 1) """ ) try db.execute( """ INSERT INTO "reminders" (title, "remindersListID") VALUES ('Call accountant', 2) """ ) } return database } Nothing too special here and I’m sure by now all of our viewers are intimately familiar with this kind of set up for a database.
— 2:54
Things get more interesting when we see how we can interact with this database. We’ll start off simply. To start a read-only transaction with the database to perform queries, like say selecting all reminders lists, we can do the following: @Test func read() async throws { try await database.read { db in try #expect(db.query("SELECT * FROM remindersLists").count == 2) } }
— 3:49
Pay no attention to the fact that we are using raw SQL strings here instead of our fancy query builder. Our motivation here is not to build the most robust, future-proof database client, but rather show how one can enforce correctness in the database client using all of the modern concurrently tools Swift has to offer.
— 4:16
Behind these scenes of this seemingly simple database call is an actor that controls a pool of readers. The await we see here is first to get inside the reader actor, and then it further suspends if all readers in the pool are busy. But if a reader is free, then without missing a beat we are able to acquire the reader and start executing with it almost immediately. This is using almost every fancy concurrency tool in the box to squash every single unnecessary suspension point and get us to executing our query as quickly as possible. And the most amazing part? There is not a single lock being used in this entire process and no blocking code whatsoever.
— 5:09
Now, a big problem that people have with actors is that they seemingly make everything async. Since you have to await to get access to any property or method in an actor, it stands to reason that you must always have an async sequence to interact with an actor.
— 5:24
But that is not the case. And to prove it, we are able to provide a synchronous version of read that can be called when there is no async context: @Test func syncRead() throws { try database.read { db in try #expect(db.query("SELECT * FROM remindersLists").count == 2) } }
— 5:39
This still has all of the same protections as the async, but it does need to use a lock to protect its connection to the database. Ideally you would always use the async interface for reading from the database because it can work efficiently during high contention without blocking, but that is not always possible and so it’s good to have an alternative when necessary.
— 6:13
We can also a quick test that shows that writes are possible in the way you would expect: @Test func asyncWrite() async throws { try await database.write { db in try #expect( db.query( """ INSERT INTO remindersLists DEFAULT VALUES RETURNING * """ ) .count == 1 ) try #expect( db.query("SELECT * FROM remindersLists").count == 3 ) } }
— 6:31
Here we inserted just default values right into the “remindersLists” table and asserted that 1 row was indeed inserted. And just to make sure we then turn right back around to query the database and prove that the table indeed does have 3 rows now.
— 6:42
And the cool thing here is that behind the scenes there is another actor that is protecting write access to the database. This naturally enforces serialization even when hundreds of tasks are trying to simultaneously write to the database, and it’s all done without a single lock in sight.
— 7:00
And so there’s nothing too surprising here yet, but it is worth noting that there is no equivalent synchronous version of the write method. Writes in SQLite can cause a lot more contention than reads do because there can only be one single writer on a SQLite database, whereas there can be many readers. So by offering a synchronous write we would make it quite easy for people to block up threads waiting for the writer to become available, whereas an asynchronous write can suspend in a non-blocking fashion until the writer is available. We even get prioritization of writes for free thanks to priority ordering in Swift concurrency.
— 7:42
And because we have properly modeled a pool of readers and a single writer as actors, we get the ability to hammer on the database as much as we want without having fear we are doing so in an invalid manner. Take for instance a test that fires up 1,000 tasks to perform writes and 1,000 tasks to perform reads: @Test func highContention() async throws { let count = 1_000 await withThrowingTaskGroup { group in for _ in 1...count { group.addTask { try await database.write { db in try #expect( db.query( """ INSERT INTO remindersLists DEFAULT VALUES RETURNING * """ ) .count == 1 ) } } } for _ in 1...count { group.addTask { try await database.read { db in try #expect( db.query("SELECT * FROM remindersLists").count > 0 ) } } } } try await database.read { db in try #expect( db.query("SELECT * FROM remindersLists").count == 1_002 ) } }
— 8:08
The writes are properly serialized in one actor while all of the reads are allowed to be performed concurrently, but there is a fixed width of how many readers can be active at once. Most applications will benefit from having a small number of readers, somewhere between half the number of cores of the device to the full number of cores, but that’s up to you to choose.
— 9:05
Another super power that was unlocked from properly integrating isolation into these tools was the ability for us to have precise control over exactly when and where changes to the database are delivered when observing queries: @Test func observation() async throws { }
— 9:19
In particular, when we observe changes to the database like so: try await database.observe( on: <#SQLiteDatabase.ObservationDelivery#>, <#(borrowing SQLiteDatabase.Reader) throws -> sending [AnyRow]#>, onResult: <#(Result<[AnyRow], any Error>) -> Void#> )
— 9:28
…we get to choose whether those events are delivered to a particular actor, in an unstructured task, or a detached task: .actor .detached .task
— 9:44
Each of those can have their use cases, but even better, when no delivery method is provided it defaults to synchronously notify as soon as the write actor is freed up: try await database.observe( <#(borrowing SQLiteDatabase.Reader) throws -> sending [AnyRow]#>, onResult: <#(Result<[AnyRow], any Error>) -> Void#> )
— 10:02
What you do is execute your query in the first trailing closure: try await database.observe { db in try db.query("SELECT title FROM reminders") } onResult: { result in }
— 10:13
…and then whenever the database changes that would affect this query the onResult trailing closure will be called. To prove that this works let’s get some protected mutable state in place: let titles = Mutex([[String]]())
— 10:34
…and when onResult is invoked we will append to that state: let subscription = try await database.observe { db in try db.query("SELECT title FROM reminders") } onResult: { result in titles.withLock { $0.append( try! result.get().compactMap { $0["title"] as? String } ) } } defer { withExtendedLifetime(subscription) {} }
— 11:36
To prove this works we will execute a query that appends an exclamation mark to the title of every reminder, and then assert that the mutable state has changed to show that the titles indeed have exclamation marks: try await database.write { db in try db.execute("UPDATE reminders SET title = title || '!'") } #expect( titles.withLock { $0 } == [["Get milk!", "Call accountant!"]] )
— 12:19
This test passes in a tiny fraction of a second, and we can run it 1,000 times and it still passes.
— 12:33
It may not seem like it, but this is actually incredible. The ability to synchronously deliver changes to observes while simultaneously not holding up the writer is incredibly difficult to do, but we were able to do is so easily thanks to Swift’s isolation tools. We are able to wiggle ourselves into the exact moments we move from one isolation domain to another to make sure we don’t accidentally block the writer, which would be quite the problem since there is only one of them.
— 13:07
And to get a small peek behind the curtain we can put a break point inside the onResult , run the test, and we will see we get caught with the following stack trace: #0 0x000000010a380ac8 in closure #2 in SQLiteIsolationTests.observation() at …/Tests/SQLiteTests/EpisodeTests.swift:173 #1 0x000000010a4b1160 in PendingObserverNotification.deliver() at …/Sources/SQLite/WriterConnection.swift:244 #2 0x000000010a4b1004 in WriteResult.deliverNotifications() at …/Sources/SQLite/WriterConnection.swift:226 #3 0x000000010a49ea78 in SQLiteDatabase.write<()>(_:) at …/Sources/SQLite/SQLiteDatabase.swift:128 #4 0x000000010a37fbf4 in SQLiteIsolationTests.observation() at …/Tests/SQLiteTests/EpisodeTests.swift:182
— 13:18
This is a surprisingly tiny stack trace that leads from the where the write is happening in our test, through the library, and ending in the onResult closure. And in one of the stack frames we will find exactly where notifications are delivered: nonisolated(nonsending) public func write<T>( _ body: sending (borrowing SQLiteDatabase.Writer) throws -> sending T ) async throws -> sending T { try Task.checkCancellation() let result = try await writer.write(body) result.deliverNotifications() return result.value }
— 13:46
And the most important thing to note is that delivery of notifications is happening right after writer.write , which is the actor, and the method we are in nonisolated(nonsending) . This means that if any of our observers take a long time to process the event, they will only be holding up the caller of write , but they will not be holding up others from writing to the database. The writer is freed up immediately and ready for action if anyone wants to write to the database.
— 14:29
And if you decide you do not want to hold up the caller of write then you can always use the on argument to choose another delivery method, such as a task or actor.
— 15:00
So already this is amazing, even at a surface level without looking at the nitty gritty details of this code. We are encoding very strict and succinct concurrency rules into this library that are enforced at compile time rather than runtime. And we were able to accomplish all of this without really a single escaping closure, no unsafe or unchecked tools used, and we even largely limited the number of things that needed to be sendable along the way. It truly embraces structured concurrency as much as possible.
— 15:30
And so this style of API helps you use it correctly from the very beginning. If you use it incorrectly you are met with a compiler error rather than a runtime crash or warning. And that brings us to something else amazing that we were able to encode in this library. By making use of Swift’s ownership tools we were able to completely prohibit people from doing things that we know are bad. For example, the db handed to the read and write trailing closures: try database.read { db in … }
— 16:07
…technically under the hood hold onto a pointer that represents the connection to the SQLite database. Passing around pointers like this is very dangerous, and it would be disastrous if we allowed our users to get ahold of this thing and do whatever they want with it.
— 16:24
But thanks to Swift’s ownership tools we have compile time proof that the user can never escape this value outside of contexts that we don’t want them to. For example, we of course would never want someone firing up an unstructured task to escape the db connection to interact with it: @Test func cantEscapePointer() throws { try database.read { db in Task { db } } }
— 16:40
This would be disastrous because we can no longer serialize access to the pointer or control when or how it is used. And thankfully because the read method only lends us the connection and does not allow us to consume it, we are immediately met with a compiler error: ‘db’ is borrowed and cannot be consumed
— 17:03
And if we tried escaping the pointer by returning it from read : @Test func cantEscapePointer() throws { let db: SQLiteDatabase.Reader = try database.read { db in return db } }
— 17:13
…again we are met with an error letting us know that this is only possible if Reader is copyable, which it is not: Instance method ‘read’ requires that ‘SQLiteDatabase.Reader’ conform to ‘Copyable’
— 17:22
And we can’t even assign an implicitly unwrapped optional that is defined outside of read : var db: SQLiteDatabase.Reader! try database.read { db = $0 } Implicit conversion to ‘SQLiteDatabase.Reader?’ is consuming
— 17:36
So this is incredible for us as library maintainers to make sure we do not allow our users to do things that we know will be dangerous, and great for our users to naturally guide them towards safer behavior.
— 17:49
But we went above and beyond. All of what we are seeing right now is thanks to the non-copyable feature of Swift, which we can see in the definition of Reader : public struct Reader: ~Copyable, ~Escapable { … }
— 18:00
That little annotation makes it so that Swift will not allow values of this type to be passed around willy or nilly. There must be a unique owner of the value, and when passing it to another function you must specify whether you are only lending them the value or if you are transferring ownership to the caller.
— 18:17
And this Reader holds onto a Connection : struct Connection: ~Copyable { let id: UUID private let rawValue: OpaquePointer private let statementCache: StatementCache … } …which is the type that holds onto the pointer which is the precious state that we want to protect and prevent from being misused. And note that it the pointer is private so that it can’t ever even be accessed from any code that is not defined in this exact file.
— 18:43
So all of that is great, but you may have noticed another annotation on Reader : public struct Reader: ~Copyable, ~Escapable { … }
— 18:50
The reader is also non- escapable , which is a newer feature than non-copyable, and it severely restricts how this value can be stored. In particular, it is not allowed to be stored in a type whatsoever. It can be constructed and passed to various functions and closures, but at the end of that lexical scope it must be released and is no longer valid to be interacted with.
— 19:17
For example, if we ever tried defining a new type to hold onto a Reader : struct Foo: ~Copyable { let reader: SQLiteDatabase.Reader }
— 19:27
…we are immediately met with a compiler error: Stored property ‘reader’ of ‘Escapable’-conforming struct ‘Foo’ has non-Escapable type ‘SQLiteDatabase.Reader’ It is not legitimate to hold onto a reader for longer than a lexical scope, and so that keeps us honest with how we use this type.
— 19:31
And that is exactly how it is used in the library, as can be seen from this internal helper: @_lifetime(borrow connection) func withReader<R>( from connection: borrowing Connection, _ body: (borrowing SQLiteDatabase.Reader) throws -> sending R ) rethrows -> sending R { try body(SQLiteDatabase.Reader(connection: connection)) } The body trailing closure is like what is handled to the read and write , and we simply construct a Reader , hand it to the closure, and then do nothing else with it. We couldn’t do anything else even if we wanted. We simply cannot store this value.
— 19:48
And this gives us, as library maintainers, that in the future as this library evolves and becomes more complex we never do anything dangerous. We should never be able to store these values because it’s whole purpose is for a very brief amount of time hand out a database connection to the user’s code, while at the same time not expose the using to any of the functionality in the connection, especially its underlying pointer. TCA2 + SQLiteData
— 20:21
So this is all pretty incredible. This is showing that by correctly using some of Swift’s most advanced tools we are able to provide a safe, performant interface to our users for interacting with a C library:
— 20:34
It automatically handles concurrency without the user having to think about it.
— 20:38
It prevents the user from doing dangerous things with the values and objects vended by the library, such as the database connection.
— 20:44
It can produce code that is shockingly efficient, minimizing both stack frames and memory allocations.
— 20:50
And it may surprise users, but we were able to accomplish this while simultaneously minimizing how many sendable types are in the library. In fact, a major theme of this upcoming series is going to be about avoiding sendability when possible. Stephen
— 21:05
But can you believe it gets better?
— 21:07
We have now shown that the Composable Architecture has had amazing benefits from properly adopting isolation and non-copyable types, and then we saw that a theoretical tiny library for interfacing with a C library also hugely benefits from isolation, non-copyable types, and even non-escapable types.
— 21:23
And now what if we put those two things together? What if we said that all of our hard work to encode all of the semantics of these two libraries into the static types as unlocked all new super powers that, in all honesty, just a week or two ago we did not thing was possible. We are extremely excited to share what we consider the best testing experience on the planet when it comes to building apps that use SQLite.
— 21:47
Let’s take a look.
— 21:51
I am back in our TCA26 project, which remember is our re-imagining of the Composable Architecture for 2.0 that is not yet integrated into the main repo. And I’ve got a tiny demo built that uses both the Composable Architecture as well as our popular SQLiteData library. We have not spent any time on how to use SQLiteData with TCA, and that’s largely because we just weren’t very happy with the test story, but now that has all changed.
— 22:14
We are running the demo feature in the preview right now, and it’s really nothing special. We have the ability to add counters to this screen, and we can increment and decrement any specific counter. And behind the scenes all of this data is being stored to SQLite using our SQLiteData library.
— 22:32
Let’s take a look at the feature code. We have a Counters feature that puts the @FetchAll property wrapper directly in the state. This is how we recommend one integrates SQLiteData into TCA features, and it mimics what one does in vanilla SwiftUI: import SwiftUI import TCA26 @Feature public struct Counters { public struct State { @FetchAll var counters: [Counter] public init() {} } … }
— 22:50
Also in the feature we have a dependency on the database: @Dependency(\.defaultDatabase) var database
— 22:54
And then in the body of the update we perform various queries when certain actions are sent: Update { state, action in switch action { case .addCounterButtonTapped: return .run { _ in try await database.write { db in try Counter.insert().execute(db) } } case .decrementButtonTapped(let id): return .run { _ in try await database.write { db in try Counter .find(id) .update { $0.count -= 1 } .execute(db) } } case .deleteButtonTapped(let id): return .run { _ in try await database.write { db in try Counter.find(id).delete().execute(db) } } case .incrementButtonTapped(let id): return .run { _ in try await database.write { db in try Counter .find(id) .update { $0.count += 1 } .execute(db) } } } }
— 23:07
Writing to the database should always be done in effects, and this is enforced now due to the fact that database.write is always asynchronous and never synchronous.
— 23:15
So, that is all there is to the feature. Let’s see what it looks like to write a test. I’ve already got some basic scaffolding in place: import TCA26 import Testing @testable import Demo extension BaseTests { struct DemoTests { @Test func basics() async { let store = await TestStoreActor( initialState: Counters.State() ) { Counters() } } } }
— 23:29
We would like to emulate the user tapping on the “Add” button and then assert on what happened in the state: await store.send(\.addCounterButtonTapped) { <#???#> }
— 23:40
But the question is… what can we possibly assert on in here? The counters state: await store.send(\.addCounterButtonTapped) { $0.counters } …in the feature’s state is technically not mutable. It is owned by the @FetchAll property wrapper, and it’s exposed as read-only state. And the reason for that is because the source of truth of this state lives in a SQLite database, and when the database changes those changes are played back to this state. So it wouldn’t make sense for you to be able to mutate the state.
— 24:01
But that does leave testing in a difficult spot because the Composable Architecture prides itself on being able to exhaustively test its features. And so the way we’ve be recommending to people to handle this is explicitly load the freshest data into the @FetchAll projected value: store.state.$counters.load()
— 24:20
…and then immediately after we can assert on the data inside: #expect(store.state.counters == […])
— 24:32
But this is not idea for many reasons. First, it’s a bummer that we have to test this state in a completely different manner than the other state. And second, the assertion is a bit of a pain to write because we have to assert on the full state, and so we are likely to take shortcuts and increase our chances of missing certain things.
— 24:51
And so what if we told you that thanks to our hyper focus on properly handling isolation in the TCA2 and this little SQLite toy library we are playing around with, we now have the ability to write our assertion in the standard, exhaustive manner: await store.send(\.addCounterButtonTapped) { $0.counters.append(Counter(id: 1, count: 0)) }
— 25:18
And if we got something wrong in the assertion, like say we thought the count was 1: await store.send(\.addCounterButtonTapped) { $0.counters.append(Counter(id: 1, count: 1)) }
— 25:39
…then we will instantly be met with a test failure that tells us exactly what went wrong: basics(): Issue recorded: State change did not match expectation: … Counters.State.DebugSnapshot( counters: [ [0] : Counter( id: 1, − count: 1 + count: 0 ) ] ) (Expected: −, Actual: +)
— 25:45
This is all working exactly as normal test failures do in TCA apps, but we are able to capture more state than what is directly stored in our features. This state technically lives in a SQLite database, yet we are able to capture it at the exact moments we need in order give you the ability to exhaustively assert on it.
— 26:01
And we are even seeing a tiny hint of some of the magic behind the scenes with this DebugSnapshot type. This is a brand new library we are working on and will release in the coming weeks that makes it possible to provide exhaustive testing tools for things that are typically very difficult to test exhaustively, such as references types, and as is the case here, SQLite databases. We think it brings some really magical testing powers to the Composable Architecture.
— 26:23
But let’s undo that change for now so that we can get back to a passing test suite.
— 26:27
Next we can emulate tapping on the increment button for this row: await store.send(\.incrementButtonTapped, 1) { $0.counters[0].count = 1 }
— 26:45
This test passes. And then we can emulate the user deleting this counter: await store.send(\.deleteButtonTapped, 1) { $0.counters.remove(at: 0) }
— 27:01
And this passes. And it passes when run 1,000 times, it passes super quickly, and it is all happening without a single yield in our library code. Because we have so tightly integrated isolation into all of these libraries, we are able to have exact control over how everything executes. Next time: Beyond basics begins
— 27:48
We have now shown off 3 case studies of what isolation, non-copyable types and non-escapable types have been able to achieve in some of our libraries. We are able to build the next generation of both the Composable Architecture and SQLiteData that minimizes thread hops and uncertainty, minimizes sendability requirements, minimizes allocations, and allows us to build all new tools in this library that we previously thought was just impossible. Brandon
— 28:11
And so now the only thing left is for us to start diving into these topics so that everyone can understand at a deep level how we were able to accomplish what we just demonstrated. Our “Beyond the Basics” series is going to be done in 3 movements:
— 28:25
First we will give a comprehensive overview of isolation, which is a topic that sadly has a lot of misinformation in the Swift community and we are going to bust some mythes. Stephen
— 28:35
Then we will discuss non-copyable types and show how they allow you to protect precious bits of state and drastically improve the performance of hot paths in your code. Brandon
— 28:44
And then we will discuss non-escapable types to show how they allow you to further lock down what one can do with types which can help you provide temporary, safe and performant “views” into other types.
— 28:58
So, we have a lot to cover, and I think what we are going to show is going to blow people away.
— 29:04
Until next time! References SE-0390: Noncopyable structs and enums Joe Groff, Michael Gottesman, Andrew Trick, Kavon Farvardin • Dec 7, 2022 This proposal introduces the concept of noncopyable types (also known as “move-only” types). An instance of a noncopyable type always has unique ownership, unlike normal Swift types which can be freely copied. https://github.com/swiftlang/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md SE-0446: Nonescapable Types Andrew Trick, Tim Kientzle • Feb 5, 2024 We propose adding a new type constraint ~Escapable for types that can be locally copied but cannot be assigned or transferred outside of the immediate context. This complements the ~Copyable types added with SE-0390 by introducing another set of compile-time-enforced lifetime controls that can be used for safe, highly-performant APIs. https://github.com/swiftlang/swift-evolution/blob/main/proposals/0446-non-escapable.md SQLiteData Brandon Williams & Stephen Celis A fast, lightweight replacement for SwiftData, powered by SQL. https://github.com/pointfreeco/sqlite-data Downloads Sample code 0356-beyond-basics-isolation-pt2 Point-Free A hub for advanced Swift programming. Brought to you by Brandon Williams and Stephen Celis . Content Become a member The Point-Free Way Beta previews Gifts Videos Collections Free clips Blog More About Us Community Slack Mastodon Twitter BlueSky GitHub Contact Us Privacy Policy © 2026 Point-Free, Inc. All rights are reserved for the videos and transcripts on this site. All other content is licensed under CC BY-NC-SA 4.0 , and the underlying source code to run this site is licensed under the MIT License .