Archive for March 1, 2024

Friday, March 1, 2024

Should Game Porting Toolkit Be Built-In?

Dan Moren (Mastodon):

What a difference eight months makes. That’s in no small part due to Whisky, an app that wraps both Wine, the tool that translates Windows API calls to their Unix-like equivalents, and Apple’s game porting toolkit into one very friendly interface. That removes pretty much all of the work out of the process, to the point where all I had to do was download Whisky and drag it into my Applications folder. It installed all the necessary under-the-hood software, leaving me with nothing but time on my hands.

So I grabbed the standalone installer for Dark Forces that I’d purchased from and simply ran it. Less than ten minutes later, I was running around blasting pixelated stormtroopers. I even connected the Xbox controller I keep in my office and it worked seamlessly, with no additional setup (I was surprised to see that even Dark Forces’s in-game UI knew I was using an Xbox controller and changed to reflect that).


If Apple really wants to jumpstart gaming on the Mac, it should bake the underlying technologies of the game porting toolkit directly into the system. Make installing and running a PC game as easy as if it were a Mac native title.


In the end, I’d argue that the potential benefits outweigh the risks: running PC games on the Mac at all is a pretty big coup, to say nothing of them running pretty well. If Apple’s really worried about a bad experience reflecting poorly on its products, it can throw up a splash screen disclaimer—come on, you guys love splash screen disclaimers!

And Apple is fine with Catalyst and iOS apps on Mac. Even games that are actually ported to the Mac don’t really feel platform-native, anyway.

Matt Birchler:

The Steam Deck was my favorite new thing in 2022 and its OLED successor is a beast as well. But the Steam Deck doesn’t run Windows, it runs Linux. Basically none of the games I’ve ever bought run on Linux, so why do I like my Steam Deck so much? Well, just like Moren suggests Apple do, Valve has built a tool called Proton that translates basically any Windows game (or app) to run flawlessly on Linux. And it’s not just for Steam hardware, anyone on Linux can use it!

And don’t think of it as some sort of complex tool for nerds; I’d compare it to using Rosetta 2 on the Mac.


Leap Year Bugs

Deborah Pickett:

Kazakhstan, which has not observed daylight saving for 20 years, is turning the clocks back at 0:00 on 1 March 2024, to 23:00 on leap day February 29 2024.

Definitely playing time zones on Hard Mode, Kazakhstan. Thanks for doing some QA on stacked edge cases for us all!

Greg Titus:

OH SURE, let’s do a daylight savings change right at midnight on a leap day. AND combine two time zone regions into one at the same time.

Rebecca Sloane:

today is the day that separates the haves read the calendar / date documentation from the have-nots read the docs but my custom logic works so I’m shipping it

Sami Samhuri:

It’s a great day to check your date math for bugs. Foundation’s calendar is forgiving and you might not want that. Using DateComponents to ask for 29-02-2023 will give you 01-03-2023.

Rachel Kroll:

Only half of the fun of a leap year happens on February 29th.

The rest of it happens in ten months, when a bunch more code finds out that it’s somehow day 366, and promptly flips out. Thus, instead of preparing to party, those people get to spend the day finding out why their device is being stupid all of the sudden.

Scharon Harding (Hacker News):

As reported by numerous international outlets, self-serve pumps in New Zealand were unable to accept card payments due to a problem with the gas pumps’ payment processing software.

See also: Did you encounter any leap year bugs today?.


Time 1.0.0 Swift Package

Dave DeLong:

Four years ago I introduced Time 0.9.0. It is appropriate that today, on its first birthday, it finally graduates to 1.0.0!


All “fixed values” keep track of their calendar, locale, and time zone, enabling you to easily work with calendar values from around the world with the knowledge that their relative calculations are correct.

Beyond this, Time has numerous other capabilities, including:

  • Creating clocks in any combination of calendar, locale, or time zone
  • Creating clocks that move faster or slower than real time to facilitate testing time-dependent code
  • Adopting the RegionalClock protocol to create your own clocks for controlling time
  • Listening for time changes via a Combine publisher or AsyncSequence
  • Retrieving the Range<Instant> for any calendar value
  • Converting calendar values between time zones, locales, and calendars
  • Truncating calendar values to get their containing units
  • Finding differences between calendar values
  • Offsetting (adjusting) calendar values by specific amounts

It’s built on Foundation.

Dave DeLong:

Well, the main reason for the delay is that I was working at Apple, where it’s extremely difficult to get permission to work on open source projects. I left that job about 3 weeks ago, so the past couple of weeks have been me frantically getting the 1.0 version ready for today.


How the Swift Compiler Knows That DispatchQueue.main Implies @MainActor

Ole Begemann (Mastodon):

A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on DispatchQueue.main, in exactly that spelling.


Fun fact: since this is a purely syntax-based check, if you define your own type named DispatchQueue, give it a static main property and a function named async that takes a closure, the compiler will apply the same “fix” to it. This is NOT recommended[…]


The biggest benefit of Swift’s concurrency model over what we had before is that so many things are statically known at compile time. It’s a shame that the compiler knows on which executor a particular line of code will run, but none of the tools seem to be able to show me this. Instead, I’m forced to hunt for @MainActor annotations and hidden attributes in superclasses, protocols, etc. This feels especially problematic during the Swift 5-to-6 transition phase we’re currently in where it’s so easy to misuse concurrency and not get a compiler error (and sometimes not even a warning if you forget to enable strict concurrency checking).

Doug Gregor:

The @MainActor attribute is the general thing, and if DispatchQueue.main returned a MainDispatchQueue type whose async method took a @MainActor closure, we’d be all set. The problem with this specific case is that DispatchQueue.main already has a type (DispatchQueue), and you can’t change that type without affecting source compatibility. So you would need some generalization that tries to carry MainActor-ness along with the value. I suspect that such a generalization would generalize to, basically, just this API, so I didn’t pursue it. Given the choice between breaking source compatibility for DispatchQueue.main (which is everywhere), inventing a bespoke feature for these cases alone, or allow-listing this pattern to help more code “just work”… I think this was rhetorical right call. Maybe we should have also deprecated this pattern over to move to an API that does take a @MainActor closure, so the allow-list would become irrelevant over time.

Holly Borla:

You might be interested in this pitch which replaces @_inheritActorContext with a proper, non-underscored @inheritsIsolation attribute, including replacement in Task.init.

Der Teilweise:

Everything about warnings is completely broken in Xcode.

When I turn on the concurrency warnings in 15.3ß3, I get ~40 warnings that disappear half a second after I click them (and come back when I switch away from the file).


Where View.task Gets Its Main-actor Isolation From

Ole Begemann:

SwiftUI’s .task modifier inherits its actor context from the surrounding function. If you call .task inside a view’s body property, the async operation will run on the main actor because View.body is (semi-secretly) annotated with @MainActor. However, if you call .task from a helper property or function that isn’t @MainActor-annotated, the async operation will run in the cooperative thread pool.


  1. The View protocol annotates its body property with @MainActor. This transfers to all conforming types.

  2. View.task annotates its action parameter with @_inheritActorContext, causing it to adopt the actor context from its use site.

Sadly, none of these annotations are visible in the SwiftUI documentation, making it very difficult to understand what’s going on. […] To really see the declarations the compiler sees, we need to look at SwiftUI’s module interface file.


When used outside of body, there is no implicit @MainActor annotation, so task will run its operation on the cooperative thread pool by default. (Unless the view contains an @ObservedObject or @StateObject property, which somehow makes the entire view @MainActor. But that’s a different topic.)

Der Teilweise:

Swift concurrency is a mess.

Every software framework that tries to automagically do “the right thing” is doomed to break your code in the most unexpected way.

Add a new member variable and it changes execution of unrelated parts from concurrent to serial. How wild is this?

BJ Homer:

Currently, we can infer @MainActor on an entire type based on the presence of certain property wrappers within that type. TL;DR: I’m making a case that that’s a bad idea, and we should reconsider it if possible.