❌

Normal view

SpamSieve 3.3.1

15 July 2026 at 19:53

SpamSieve 3.3.1 is an update of my Mac e-mail spam filter that improves the filtering accuracy and includes various optimizations, fixes, and updates for macOS 27. Some interesting engineering issues were:

  • I’m still supporting macOS 10.13, but the app can now build with the macOS 12 deployment target in preparation for Xcode 27. The way Swift handles calling deprecated APIs remains annoying. You need workarounds like protocols to suppress a warning in a particular region of code. Often, I am updating to a newer API, but I want to continue using the old one on earlier versions of macOS. Right now I am heavily testing on macOS 26, so I would like to only deploy the new code there. Sometimes the initial versions of APIs are buggy, and I don’t want to have to retest every feature on every version. But Swift doesn’t like me to gate the calls to macOS 26 and later if the new API was actually introduced in, say, macOS 11.

  • The most risky update was probably switching to the Swift API for Scanner. This is tricky because the current scan position changes from being based on UTF-16 indexes to String.Index. And in some cases my code was intentionally scanning into the middle of a combining character. I was really glad to have extensive tests here.

  • Recent versions of Tahoe introduced a Core Data bug that broke save recovery (when invalid Unicode can’t be written to the database and we have to fix it up first). When the error comes in, SpamSieve looks under the NSDetailedErrorsKey key, but the value of this key is "NSDetailedErrorsKey" while the actual error info is under the key "NSDetailedErrors".

  • Database corruption combined with a Core Data bug and two Swift behaviors were causing crashes. The root problem, I think, is that in this situation Core Data neglects to set the error pointer for -[NSManagedObjectContext countForFetchRequest:error:]. Normally, Swift would detect this and throw a generic nilError. However, this method signals errors by returning NSNotFound instead of nil. It’s annotated as swift_error(nonnull_error), which I think means that Swift doesn’t even look at the return value, only the (unset) error. So my code was receiving NSNotFound on the non-error path, treating it as a real count, and doing some math with it, which (by default in Swift) leads to a crash if there’s overflow. Now my code checks for NSNotFound and uses Int.addingReportingOverflow().

  • I reimplemented Core Data batch fetching because of two problems with the fetchBatchSize option. First, it logs spurious errors when fetching from multiple stores at once. Second, it leads to high memory use. It will load objects in batches, but it never releases the earlier batches. You can manually refault objects that you no longer need, but it will still hold onto the full object shells, which can add up. My implementation only holds onto IDs, and it can fetch the IDs using a different context than the objects to push more work to background threads.

  • I’m now using String.makeContiguousUTF8() in various places to avoid slow iteration of bridged strings.

  • There was a regression where some menu code could crash on macOS 10.13. -[NSMenu setItemArray:] is only available on macOS 10.14 and later, whereas the getter is always available. With old Objective-C, the two methods could be annotated with separate availabilities. The Objective-C property syntax doesn’t allow this, so there’s no way for the compiler to flag calls where the setter is missing.

  • The AppleScript support works much better with large data sets. The key, I think, is to never return an array to Cocoa for a scripting property/element. First, if you give it a lazy array it will sometimes try to access all the elements even if it only needs a few. And, second, AppleScript will run out of memory if the array is too large. By using indexed accessors, you can maintain laziness and only convert one object to a descriptor at a time. By caching a batch-fetching collection, you can limit the number of fetches and respond quickly when AppleScript requests individual objects.

Previously:

Swift 6.4

24 June 2026 at 21:54

Swift 6.4 is now available in beta form with Xcode 27. The Swift Evolution proposals are listed here.

What’s new in Swift:

Discover the latest language advancements, including updates for everyday ergonomics, improved concurrency, and safer high-performance code. Explore workflow and language interoperability improvements and updates in embedded Swift.

Build real-time apps and services with gRPC and Swift:

Build engaging live experiences with gRPC in your Swift app and backend. gRPC is an open-source RPC framework designed for high-performance, bidirectional streaming APIs. Explore how the gRPC Swift package provides a modern, safe runtime built with Swift concurrency.

Explore numerical computing in Swift with MLX:

Bring NumPy-style computing natively to Swift with MLX Swift. Discover how to eliminate cross-language friction in your machine learning workflows by handling image processing, tensor operations, and neural network training in a single, type-safe environment. Explore the APIs that let you leverage GPU acceleration while enjoying the compiler, tooling, and debugging experience you already know.

Swift Group Lab:

Join us online for a deep dive into WWDC26 with Apple engineers and designers to ask questions, get advice, and follow the discussion about the week’s biggest Swift announcements.

Matt Massicotte:

There’s a voting system. And that means a number of questions weren’t selected. This time I copied those down and I thought it could be fun to take a shot at answering the ones that are more in my area.

Xcode 27 Beta 2 Release Notes:

The Swift dependency scanner has been optimized to avoid redundant setup work and header searches when looking up Clang modules during a single dependency-scan action, substantially improving scanning performance.

As a consequence of this change, every Clang module reachable from a single Swift dependency-scan action must have a unique module name. If two module maps visible to the same scan declare a Clang module with the same name, the scan may report an error.

[…]

System now provides Swift APIs for the C stat, lstat, fstat, and fstatat system calls. This includes a new Stat type with initializers from FilePath, FileDescriptor, or a C string; FilePath.stat() and FileDescriptor.stat() instance methods; and supporting types (FileType, FileMode, FileFlags, UserID, GroupID, DeviceID, and Inode).

Wade Tregaskis:

The final piece of the Prospective Vision for Accessors, this allows for more efficient accessors on structs, in a nutshell.

[…]

Now there’s a safer version of the existing withUnsafeTemporaryAllocation (first introduced in Swift 5.6). It works just like you’d expect. It comes in both “raw bytes” and typed elements versions, just like its unsafe predecessor.

[…]

The new isTriviallyIdentical(to:) method offers a guaranteed-fast way to check two objects for equality. It is essentially an optimised version of the existing equality condition provided by Equatable and the == operator. It’s useful because it guarantees O(1) time complexity, whereas == makes no formal guarantees at all (and for many types is O(N) or worse). But unlike the existing identity comparison operator === – also O(1) – it promises to do more than just tell if two objects are the exact same pointer, and it works on value types (not just reference types).

[…]

These new types generalise the existing patterns of borrowed and mutable references, that have previously existed in Swift in much more restricted forms (e.g. inout parameters are essentially MutableRef parameters, and Span & MutableSpan are array equivalents).

There’s now a built-in function for demangling Swift symbol names, in the Runtime module (that’s bundled with the Swift toolchain, alongside the stdlib etc).

Khoa Pham:

As Apple has aligned OS version numbers across platforms, Swift 6.4 takes the next step by letting you collapse repetitive availability attributes into a single anyAppleOS token.

[…]

There are situations where you need to call a deprecated API while you plan a migration, or audit a critical function for unsafe usage, without letting those concerns bleed into the rest of the project. The new @diagnose attribute handles both cases.

[…]

Some work should complete even after a task is cancelled, like flushing a file to avoid corruption. withTaskCancellationShield wraps a region where Task.isCancelled always returns false.

Antoine van der Lee:

Swift 6.4 implements SE-0493: Support async calls in defer bodies. This is one of those changes that feels obvious once you need it.

[…]

Swift 6.4 improves error handling for unstructured tasks through SE-0520: Discardable result use in Task initializers. The change helps you catch a subtle bug: creating a throwing task and then ignoring its returned task handle.

[…]

Swift 6.4 also implements SE-0530: Async Result Support.

[…]

Swift 6.4 implements SE-0518: ~Sendable for explicitly marking non-Sendable types. It allows you to communicate that a type has been audited and should not conform to Sendable.

Slava Pestov:

I thought it would be a good time to detail some of the type checker performance improvements we worked on since I shared the type checker performance roadmap last year. I’m also going to outline a couple of things we plan on looking at next.

Previously:

Update (2026-07-09): I was optimistic about improvements to the type checker making compilation faster, but I found that compiling my predominantly Swift project with Xcode 27 Beta 3 was only 0.3% faster than with Xcode 26.6. I wonder if there’s some extra setting I’m supposed to enable.

Rewriting Apple’s TrueType Hinting Interpreter in Swift

12 June 2026 at 20:34

Scott Perry:

My team rewrote Apple’s TrueType hinting interpreter in Swift, ask me anything.

[…]

I feel like naming just one would be a disservices to all of the features that made this effort possible (C interop, generics, noncopyable/nonescapable types) but at the end of the day I think the star of the show was the optimizer; despite being faster than the code it replaced, the new code is super readable and that was only possible because the optimizer was able to completely eliminate all of our abstractions.

The new version is faster, but the main motivation was security concerns.

Dmitrii Kalianov:

Is hinting useful/being used in the days of hi-dpi displays? I was under impression that Apple switched to grayscale anti-aliasing and ditched hinting.

Scott Perry:

For the most part hinting isn’t really necessary anymore, but thanks to being Turing-complete it has been Hyrum’s law-ed by at least one CJK font that uses hinting to lay out strokes in its characters.

Alex Rosenberg:

There were three major TrueType implementations at Apple IIRC:

  • The original 68K one
  • A rewrite for Copland that lived with ATS/ATSUI after Copland was cancelled
  • iPhone shipped one derived from heavily-modified FreeType that was current until today

Scott Perry:

One of the axioms for this project was that I wanted my team to write the most boring code possible—nearly identical structurally to the code it was replacing, because to do otherwise would introduce binary compatibility risk. The other axiom was 100% test coverage for all new code as it landed, with the same units testing both interpreters.

Rosyna Keller:

Is the font parsing code itself still C++?

Scott Perry:

There is also a “Safe Font Parser” for WebKit in Lockdown Mode, but it supports a subset of all the myriad features provided by font formats.

Previously:

Update (2026-06-16): Scott Perry (Hacker News):

Font parsers process data from untrusted sources, making the TrueType hinting interpreter a security-critical attack surface. To make the format more resilient on Apple platforms, we rewrote its hinting interpreter from C to memory-safe Swift for the Fall 2025 releases. In addition to memory safety, we also improved performance: on average, our Swift interpreter runs 13% faster than the C interpreter it replaced.

[…]

Binary compatibility was crucial for this project to succeed: existing programs had to continue to function the same as they did before, effectively unaware that a new implementation was in place. This means not just interface compatibility but pixel-identical glyph rendering as well, relative to the C implementation.

[…]

To ensure correctness, we developed two test suites. The first was a unit test suite that can target both implementations, providing exhaustive (99.7%) code coverage for both. This suite is included with the open source release of the Swift interpreter.

Then, to represent real-world workloads, we used a fuzzer to minimize a corpus of 10 million PDF files down to 4,200 without any loss of code coverage.

[…]

Following WebKit’s Safer Swift Guidelines, the example below demonstrates how to wrap a bridged structure from C in a projection type that uses Ref for lifetime safety, brokers bounds-safe access to the underlying data, and returns idiomatic Swift types to its callers.

The interpreter source is on GitHub.

Marcin Krzyzanowski:

@_lifetime(copy code, copy twilightZone, copy glyphZone)

See also: Phillip Tennen’s Writing a TrueType font renderer (Hacker News).

Previously:

Glow Leopard

9 June 2026 at 19:11

Tim Hardwick:

Apple at WWDC 2026 today said it has made several responsiveness improvements across its software ecosystem, speeding up system animations, app launching, and much more.

Zac Hall:

Overall, iOS 27 so far is a major collection of performance improvements and refinements.

Ryan Christoffel:

As had been rumored leading up to today, Apple has spent extra time this year working on bug fixes and performance improvements for iOS 27.

Adam Engst:

Although there’s no obvious connection between the Tahoe and Golden Gate names to indicate a “tock” release, Apple devoted the first chunk of the WWDC keynote to how OS 27 will address user and developer complaints about OS 26.

[…]

Apple also made a big deal about performance improvements, smoothing system animations, launching iPhone and iPad apps up to 30% faster, displaying new photos in the Photo Library up to 70% faster, transferring files via AirDrop up to 80% faster, and moving files from an iPad to an external drive is up to 5x faster, so it compares with macOS transfer speeds. A new CPU Scheduler promises to improve iPhone performance even on older models back to the iPhone 11, which may encourage more people with older iPhones to upgrade.

Kyle Howells:

There really aren’t many changes this year.

I’m way more interested in bug fixes, but optimizations and refinements are great, too. Simply limiting the number of new features creates space to improve the software quality, though, it’s not clear to me whether there are really fewer new features or if it’s just that they mostly fall under the single heading of AI.

Paul Hudson:

Animations run smoother, apps launch faster, and Liquid Glass is better? It’s Glow Leopard for sure!

Divya Ravi:

One underrated theme from this WWDC is Apple investing heavily in fundamentals.

Faster launches, scheduler improvements, search infrastructure, networking transitions, rendering performance…

Users notice responsiveness long before they notice most new features.

Clarko:

You gotta admire Apple’s ability to market “bug fixes and performance improvements” so effectively.

Please just do this every other year.

Previously:

Update (2026-06-12): David Smith:

Something I’ve noticed about performance work is that people really want there to be A Cause for improvements. A new technology, something old no longer holding things back, “removing the debug logging”, etc…

The truth of the matter is that 97% of the time the enabling thing for performance work is engineers having time in the schedule to sit down with the tools (usually a sampling profiler) and grind out small wins over and over.

There’s no magic bullet that replaces good engineering.

It sounds like the magic bullet is a reasonable release schedule. You’ve always had the power, my dear Craig. You just had to learn it for yourself.

Jason Snell:

The moment the keynote used the phrases “sweating the details” and “attention to detail,” it was clear that beyond AI and Siri features, this year is about small fixes and improvements. In more private settings, Apple folks specifically referenced Snow Leopard and iOS 12, two updates that saw Apple take a pause from huge feature roll-outs and prioritize speed and bug fixes a bit more.

But to be clear, referencing Snow Leopard does not mean “no new features.” Like Apple’s 27 releases, Snow Leopard was full of dozens, if not hundreds, of new features—they were just scattered small improvements throughout the system.

Patrick McConnell:

The older I get and the longer I do this development work I realize time is short and we may not get to all the things we want to do in life. So when we are forced to wait yet another year for some fixes to a framework we’ve been trying to use for several yearly cycles already it can be disappointing to say the least.

[…]

Unlike past years there is no clear Apple mandated work. Thank god. I can focus on what I want to build without having to adopt my code to an ill conceived UI update that will be semi-discarded the following year.

Update (2026-06-16): Marcin Wichary:

It’s an impressive list that garnered universally positive reactions, but I have one observation:

  • “Fast” and variants thereof appear on this list 59 times.
  • “Reliable” and similar words appear 22 times.

[…]

It’s not just me. 15 out of 17 bugs listed on the Bugs Apple Loves site are about reliability.

[…]

I just… I would be a lot more excited if the 3:1 ratio of fast-to-reliable on that slide went the other way.

❌