Archive for July 17, 2023

Monday, July 17, 2023

Chronicling 1.0

John Voorhees:

Chronicling is a brand-new event tracking app for iOS and iPadOS by Rebecca Owen. The App Store is full of apps for tracking everything from the very specific, like caffeine consumption, to apps like Chronicling that can be used to track nearly anything. What makes Owen’s app unique, though, is it’s one of the best examples of modern SwiftUI design that I’ve seen that incorporates the still relatively new Swift Charts and other recent Apple technologies to deliver a great user experience.

Trackers like Chronicling are the perfect fit for the iPhone. Most people have the device with them all the time, which makes it perfect for collecting data frequently, but it’s what you do with that data that matters the most. Maybe you’re trying to learn a new language and want to track how often you practice to hold yourself accountable. Or maybe your knee has been bothering you, and you want to keep track of when it flares up to see if it corresponds to an activity in your life. The point is, whether you’re trying to form a new habit or find patterns in things that happen throughout your day, part of the process is gathering the data. The other half of the equation is breaking the data down in a meaningful way. Chronicling does both well.

This looks really nice. To me, the line between tracking and journaling is kind of blurry. I’ve been using plain text files for both, which gives me a lot of flexibility to add comments, use a variety of tools, and sync via Git. I’m reluctant to get locked into a more specialized tool that’s rigid or may not last. But I don’t get any pretty charts unless I extract the data and make them by hand. I do get charts for some health stuff stuff tracked via the Health app and for hours tracked via ATracker. The latter is around the fourth such app I’ve used. Each week I transfer the summary data to OmniOutliner and eventually to Excel.

Previously:

Update (2023-07-18): Rereading this, I realize that it may sound like I’m implying that Chronicling locks in your data. That is not the case, as it lets you export to CSV, and this can be automated via Shortcuts. I was more thinking in general terms of changing the way I work to fit a particular tool’s design and limitations.

Macros in Swift 5.9

Platforms State of the Union:

But some APIs can be hard to use, requiring you to write a lot of boilerplate code just to get started. That’s why Swift is unlocking a new kind of API that’s easier to use and easier to get right with the introduction of macros. And these macros are done the Swift way. A macro is an annotation that uses the structure of your code to generate new code that’s built with your project. Macros can either be attached as attributes to your code, or they can be freestanding, spelled with the hash sign. Macros make APIs feel like they’re part of the language, and there are so many ways to start using a new API with just an annotation. Macros come to life in Xcode, where the generated code feels like it’s part of your project.

What’s new in Swift:

In Swift, macros are APIs, just like types or functions, so you access them by importing the module that defines them. Like many other APIs, macros are distributed as packages.

[…]

Uses of the macro will be type checked against the parameters. That means, if you were to make a mistake in using the macro, such as forgetting to compare the maximum value against something, you’ll get a useful error message immediately, before the macro is ever expanded. This allows Swift to provide a great development experience when using macros because macros operate on well-typed inputs and produce code that augments your program in predictable ways. Most macros are defined as “external macros,” specifying the module and type for a macro implementation via strings. The external macro types are defined in separate programs that act as compiler plugins. The Swift compiler passes the source code for the use of the macro to the plugin. The plugin produces new source code, which is then integrated back into the Swift program.

Write Swift macros:

Code along as we explore how macros can help you avoid writing repetitive code and find out how to use them in your app. We’ll share the building blocks of a macro, show you how to test it, and take you through how you can emit compilation errors from macros.

Expand on Swift macros:

Learn how macros can analyze code, emit rich compiler errors to guide developers towards correct usage, and generate new code that is automatically incorporated back into your project. We’ll also take you through important concepts like macro roles, compiler plugins, and syntax trees.

Antoine Van Der Lee:

In this example, we’re using a so-called freestanding expression macro. This is just one of the currently seven available different roles[…]

[…]

Xcode automatically generates a test target for you, including an example unit test for the stringify implementation.

Daniel Steinberg:

Sadly, Xcode looked at the generated code and told me that although the expanded macro was symbol for symbol what I would have typed in myself, it had no idea what those variables represented.

So I decided that what I really needed was a MemberMacro.

And by decided, I mean that based on no information and guided by no intuition, I figured that I’m trying to add new members to the type so maybe this was it.

It turned out to be the right decision.

Joseph Heck:

One of the most amazing (to me) things about this year - if you want to know HOW that fancy Observable macro works, you can just read through it.

Helge Heß:

When using the new Observation features in Swiftlang, be careful with the naming of your properties. It creates a stored property w/ an underscore in front, so don’t do the same, surprises may happen.

Also didSet doesn’t work, in case you didn’t notice yet[…]. Though the generated code actually moves the didSet to the fresh new property (not sure this is just a bug or actually impossible to do right w/ macros).

Nick Lockwood:

I’d be a lot more into Swift macros if they didn’t have to be defined in an external module (which itself depends on the external SwiftSyntax module).

To anyone used to ecosystems where apps routinely import hundreds of 3rd party packages, this probably sounds insane, but after years as an iOS dev without any sort of standard package manager, I’ve really come to value code having no dependencies outside of what ships with the platform.

Swift macros feel no more more “built-in” than Sourcery.

Ole Begemann:

If you’re writing Swift macros, you have to check out the fantastic Swift AST Explorer by @kishikawakatsumi. It makes it really easy to make sense of the syntax tree your macro operates on.

Tanner Bennett:

I’ve been experimenting with Swift macros all day trying to make “key path” decoding work. I.E., being able to supply a string like “config.meta.flag” to a macro and somehow using it to pull a value out of one or more nested dictionaries and insert it into a top-level property, without declaring nested Codable types for the nested dics.

It is not possible.

[Update (2023-07-26): See below.]

Soumya Ranjan Mahunt:

I’m excited to introduce my latest project, MetaCodable, a powerful macro library that will help you with all your Codable needs. Using MetaCodable, you can get rid of repetitive boilerplate code that you often have to write.

Dave Verwer:

The package index is already filling up with packages that contain macros, and it makes me glad we added 5.9 support so quickly. Some of the packages I’m linking to below will become essential parts of the Swift package ecosystem, and some will remain experiments. It’s impossible to know which yet!

There’s everything from full-featured packages like SwiftRequest and papyrus that let you define a type-safe HTTP client with function annotations to smaller utility packages like AssociatedObject, which allows variable storage in extensions. There are many, many more though. Here’s a list of others I saw this week:

Previously:

Update (2023-07-26): Amy Worrall:

My first foray into Swift macros.

It removes the need to write a whole bunch of boilerplate when making new Lexical nodes.

Rob Napier:

All of these are possible in a certain sense (with a custom JSON type and/or a custom AnyCodingKey type)[…]

[…]

If you start here, it’s pretty close to where I talk about stuff that I think lines up with what you’re doing.

Update (2023-07-31): See also: Daniel Steinberg’s videos.

Update (2023-08-15): Krzysztof Zabłocki:

If use Swift Macros you have to be careful how you structure your code, unlike Sourcery the Macro’s don’t concatenate whole project AST and they won’t see anything you added in Extensions to your original type…

In the example below x variable won’t be visible as a member in your macro code, this can lead to some hard to find bugs…

Apple Legal vs. Fruit Union Suisse

Gabriela Galindo (via Hacker News):

The Fruit Union Suisse is 111 years old. For most of its history, it has had as its symbol a red apple with a white cross—the Swiss national flag superimposed on one of its most common fruits. But the group, the oldest and largest fruit farmer’s organization in Switzerland, worries it might have to change its logo, because Apple, the tech giant, is trying to gain intellectual property rights over depictions of apples, the fruit.

“We have a hard time understanding this, because it’s not like they’re trying to protect their bitten apple,” Fruit Union Suisse director Jimmy Mariéthoz says, referring to the company’s iconic logo. “Their objective here is really to own the rights to an actual apple, which, for us, is something that is really almost universal … that should be free for everyone to use.”

[…]

Over the past few years, Apple has pursued a meal-prepping app with a pear logo, a singer-songwriter named Frankie Pineapple, a German cycling route, a pair of stationery makers, and a school district, among others.

Why?

Previously:

Absurdly Long YouTube Videos That Play Nothing on Purpose

David Pierce:

In this case, it turns out, the outrageous length is the whole appeal. Across all these videos and many other silent blank ones, every viewer seems to have their own use case. The most common, by far, is to use these videos as a way to simply keep your device on. “I keep this playing overnight so that my laptop doesn’t shutdown while downloading games,” one commenter wrote. “I have to keep this open on my phone because it’s broken and will not turn back on if it turns off,” another said.

There are also a surprisingly large number of times when you might want your device on but the screen off. “I use this so I can have music open on another tab at night and have this open so the screen with the music on it wont shine so bright in my room,” one commenter wrote on a two-day-long video of a blank black screen.

[…]

But you know what’s actually easier than tweaking a bunch of settings, especially for younger users accustomed to finding everything they need on YouTube? Just playing a video. One commenter on a blank-screen video called it “the perfect video to cast to your tv when you’re too tired to get up and turn it off,” which seems both ridiculous — if you can cast from your phone to your TV, you can probably use your phone to turn off your TV! — and telling.

Update (2023-07-31): Matthew Panzarino:

There’s apparently an iOS 16.x bug that deletes screen time limits on apps if your kid hits the ‘one more minute’ button. Classic. Ruining my life currently.

Jonathan LaCour:

So much this.

My kids have also figured out that they can visit YouTube in Safari, pick a super long video, enter Picture in Picture, and it completely bypasses all screen time limits.

I reported it to Apple two years ago. They acknowledged it. Still no fix.

Previously: