Bad things: Extension Access Control

Swift extends the courtesy of an access control annotated extension to its top level members. I’m going to call this “inheritance”, but I know there’s a better name for this but I just don’t know what it is.

Consider the following:

// Base type is public
public struct MyStruct {}

// Here, the extension is declared public, so each top level member
// "inherits" that access level.
public extension MyStruct {
  // This is public even if it is not annotated
  static var firstValue: String { return "public" }

  // This is also public but the compiler will warn.
  public static var secondValue: String { return "public but warned" }

  // This class is also public via "inheritance" 
  class PublicSubclass {
    // However, its members must be annotated. This is public
    public static let publicValue = "public"
    // This defaults to internal
    static let internalValue = "internal"
  }
}

In this example, firstValue inherits the public access level from the MyStruct extension. The explicit annotation for secondValue is warned by the compiler as unnecessary.  If you treat warnings as errors, that’s a problem.

Each of the static properties are accessible outside the module except for internalValue, as even in a public class declaration, its members do not inherit its control level:

Before I start putting some preliminary style guidance out there, I’d like to point out a few more things about this. Here’s a second example:

internal class InternalType {}

extension InternalType {
  public static var value: String { return "value" }
}

Swift compiles this code without error. It is clearly a developer-sourced issue. The intent to make the member public is fundamentally flawed. as it exceeds the type’s access control level. This issue also exists outside of extensions, where the compiler will not warn on too-high levels for direct type members:

internal class AnotherInternalType {
  public var value = "value" // no warning
}

You’d imagine this is a place where the compiler should up its game, no? This is a point of code that is technically functional and compilable but whose specification undercuts the documenting nature of using access control. Shouldn’t the annotation be limited and warned here?

The compiler will find mismatches between the extension ACL and the type ACL:

And that’s where the problem comes in because the guidance I’m working on says: “Do not annotate extensions with access control levels except when working with trivial utilities”. Skipping extension ACL ensures that you can meaningfully and intentionally add access control to each member declared within that extension. Each access level is co-located with the declaration it decorates. This makes your code more easily audited and its access levels will be immediately apparent as to intent and implementation.

What are your thoughts? Can you think of any reasons why extensions should ever be ACL’ed in production code? And is this just a bug/language enhancement thing or is there something I’m missing. Thanks in advance for your feedback.

Same blog, different channel

Migration done! Welcome to the new host.

After couple of days of pure hell getting things transferred and set-up, here we are. I don’t want to even think of the billable hour cost for most people making this happen. Change is traumatic.

Ended up going with siteground.com: it has cpanel, email, and WordPress. I was about theeeesclose to going with WordPress.com’s paid plan (huge huge thanks to the wonderful Jeremy Massel). In the end, there were just too many compromises. Even with siteground there were compromises, but at least it’s not Bluehost.

Thank you to everyone for your advice and recs and patience. The only thing I regret is that I forgot to get someone a referral from all this. I apologize.

If you wrote to me in the last day and it was important please try writing again just in case… There was a period of outage where the old mail hadn’t finished updating and the new mail wasn’t fully configured.

I still have to set up my mail on a bunch of different devices, so off to do that…

Fleeing Bluehost: It’s crunch time

I have under 30 days to move from Bluehost or I’ll be locked into another year. If you don’t recall, Bluehost is infuriating. It shuts down whenever I have a traffic spike. Its SSL certificates are not automatically renewed, so every 90 days or so things fail.

My email is associated with unifiedlayer, one of the worst spam providers, which means that a lot of my outgoing email never arrives. Every time I need tech support, they try to upsell me to yet another paid service. The fees have increased and increased over time.

While I’d really love to have a statically generated site, I’m not willing to give up comments. I’m sticking with WordPress as the least turbulent solution unless someone has a better idea.

I need email. I need a wordpress site. I’d like to keep a listserv going but I can probably transfer that to slack if needed. I can’t really think of any other features that I need at this time.

  • Diogene recommended SiteGround. It offers well reviewed WordPress hosting. This sounds scary though: “For migration just use IMAP for your email and synchronize all mail locally then when you move you host sync back again with IMAP”
  • Dave DeLong says FastMail is a great solution for the mail-only axis. Hank Gay, Christopher Frederick, and Dewey concur. Christopher mentions that I can set up “SPF and DKIM records” to provide more secure ownership, whatever these things are.
  • Despite the general love for FastMail, Michael Weaver says iRedMail is a good alternative as well.
  • Matt mentioned nosupportlinuxhosting.com
  • Will suggests A2Hosting. Chris likes ASPnix.com.
  • John Woolsey pitches GreenGeeks.com.
  • Nate H suggests dreamhost (also recced by Tim as a site for “people who don’t know what they’re doing”, which is pretty much me) and siteground.
  • Mark Nichols uses WebFaction, but also supports Digital Ocean.
  • Brian Anderson suggests hostagor.com.
  • Kevin likes the roll-your own AWS solution: S3 for web, EC2 for wordpress, WorkMail for mail. Any thoughts on these?
  • Simon Davies agrees on AWS but suggests hosting email with zoho.com.
  • Dan Messing and Mark Bernstein like pair.com.

I’m looking for the simplest migration with the longest shelf life and the least worries. It should remain reasonably budget affordable as well.

I want to get this done quickly and easily and it scares me to pieces. This is, admittedly, way out of my comfort zone, which explains why I’m still with Bluehost even years after identifying the problems.

Any advice and support will be greatly appreciated.

Mojave and Folderol

If you use my Folderol app, you may encounter issues in Mojave. I have not but I can confirm that some of my users have found that their folders tend to be “sticky”, and will keep their icons and folder colors even when they’ve been changed to new ones.

If this happens to you, the easiest solution is to set up a new folder, customize it with Folderol, and transfer the contents and rename it like the old one. I have reports of the issue with 10.14.3 and 10.14.2. The most common factor among those affected is that the system is running one or more UI customizations like dark mode.

Folderol works by using Apple’s NSWorkspace method that sets an icon for a file. So the actual “work” beyond creating and blending the icon is done by that class, over which I  have no control.

I’m going to try to update the app description with a warning about the problem and add a set/remove/set sequence to see if that helps.

If you’re experiencing issues with Folderol, please let me know your OS specifics, and whether you’re using custom dark mode and/or tints. Thanks!

Things I love about Apple Watch

I bought my Apple Watch to track. As I have learned over the last few months, the watch kind of stinks as a tracker and a fitness tool. It loses track of my workouts or fails to pick them up entirely. My movement in real life and my watch’s rings often fail to align. I may be wiping sweat from my brow as my watch thinks I’m taking a nap or something. And if tracking were the only thing my Watch offered, I’d write it off as an expensive failure.

Much to my surprise, though, I have fallen in love with my watch. The reasons surprise me, and had nothing to motivate my purchase. In looking back over the past months, I am constantly astonished by the watch’s convenience  and comfort (at least once I was able to get a band I could live with, because my first few attempts with the band didn’t go very well…)

Let me step back and speak of my watch’s best points.

For one thing, it lets me answer calls on my wrist. This is not a feature I would ever have wanted or searched for or asked for or desired. And yet, it’s one of the greatest things my watch does.

I bought the basic watch. It’s the one without built-in cellular so I receive calls only when my watch is near enough to my phone. I find the reach is good enough that I can answer my phone from my wrist anywhere within my house. I no longer  have to run to grab the phone from its charger. That’s amazingly convenient.

Sure it’s just weird speaking into my wrist. I’m not Dick Tracy and the ergonomics aren’t the best. And yet, I can handle a quick convo and get on with my life and I don’t have to start digging through my backpack to find the phone, which always manages to slip between things or slide into a notebook or otherwise hide itself away.

It’s a feature I didn’t know I wanted and it’s one I use daily. That alone is close to justifying the purchase price.

And, if I need to find the phone to open an app or do something that demands more real estate, I don’t worry about it slipping away in my backpack anymore. Now, I just pull up the watch’s quick utility panel and tap the phone pager. My phone pings and I instantly find wherever it has slipped. Brilliant!

But wait, there’s more.

This may sound absolutely ridiculous, but I no longer have to dig out that same self-hiding phone to look at the time. I can now glance at my wrist and the time is right there. Yes, I am the only person alive who is surprised and astonished that a watch tells you what time it is or that might be a reason for its purchase. This probably explains a lot about me.

When I put the Mickey face on the watch, I can even touch the watch without looking and hear the time. I wish that feature was available on other faces and without the creepy pedo-vibe that Mickey gives. I’ve sort of given up on Mickey because 1. pedo and 2. not enough complications (the add-ons that let you stick mini-app widgets onto the main display, kind of the “Apple Watch Dock” metaphorically) and switched to the Infographic display instead. But I love the “tap to hear the time” feature, even if I don’t use it very much.

Not only do I now know the time just by looking but my watch also tells me what date it is: perfect for writing checks, filling out forms, what have you. I don’t have to check my computer’s menu bar or drag out that phone. Again, this is about as deep into Captain Obvious territory as you get. It’s also a simple pleasure I did not consider when buying this hunk of expensive tech strapped to my arm.

And if that’s not enough, I also know what appointments are coming up next because my calendar events appear in the center of my main screen. These events travel with me no matter where I am and I can review, analyze, and plan even on the go. I didn’t realize how much I checked my schedule until I stopped looking at my calendar on my computer all the time. My watch freed me from that.

My most-used complication (again, that’s a “docked” app widget) is my timer. And I use it constantly throughout my day,  whether I’m cooking or working or doing physical therapy. I never knew how much I needed a $400+ timer on my wrist. You can pick from the presets (1 minute, 3, 5, 10, etc) or customize exactly the timing you need. I wish I could run more than a single timer at once, as there are often several things I’m doing at once. (Making waffles? 2 minutes, one after another. Stew? 90 minutes. etc)

I love how I can download audible books and music to my wrist and listen to them completely without a phone as I work out. Yes, I wish I could use the built-in speaker but even with Bluetooth-only audio, it freeing to step away from my big old 6+ and fashion-forward (yeah right) fanny pack. At some point I’m going to buy all kinds of tinkly yoga music but for right now I’m doing my PT stretches at the gym to the strains of “Funny in Farsi“.

I’m really pleased that Siri is along for the ride. I get a lot of the same utility from wristSiri as phoneSiri in terms of quick math calculations, sending a text, making a call, and so forth. I love Siri!

I’m also a big fan of both the breathe and stand app, items that have…mixed…reception and utility in the wider watch world. I use the breathe app not just to work on breathing but to exercise my back muscles and sitting strength. The stand app gives me the opportunity to stretch and move and challenge myself. I’d like to push these even further and have been shopping for a good coaching app that instills physical, mental, and personal habits via the watch. If you have any recs, let me know!

I haven’t installed many 3rd party apps on this, but I’m particularly pleased with the Just Press Record app, which does exactly what the name suggests for noting down quick thoughts when there’s no pen or paper around. On a similar note, I like that you can draw messages in the built-in texting app. It’s not ideal but it’s saved me a few times when I needed to respond to family quickly, even if the response sometimes looks like “Yes you CaN buy IT but nto mre than $10“.

I’d love to hear what 3rd party apps you’ve found that work well for you. I used the Sleep++ tracker (paid with IAP) for a while but it’s not great and I like not having to wear a wristband to bed. I also own the irritatingly meticulous Rules game, which I occasionally play when I’m desperate for something to occupy me. I feel as if I’m missing out on some great apps but I wouldn’t know where to begin.

Speaking of apps, every now and then I need a quick app that I can grab and take with me and the watch is perfect for that. To be honest, writing for watchOS is annoying (and testing is horrible) but for simple things, I can write and throw an app onto my watch for immediate use as I need it and then unload it when I don’t need it anymore. I’ve done this to scrape schedules for quick reference, to store a few important pictures to show and share, and a few other apps of various utility.

Again, this is an unexpected pleasure that doesn’t involve having to drag the phone along with me when I use them and despite the development process not being ideal, it’s a fully customizable thing that gives me the tools I need when I need them in a form that is the most portable I could imagine.

Let me finish by talking about my wristband, which I mentioned earlier in this post. When buying the watch, I first went with the sports loop, after trying all the bands on at the store. Once at home, I found it uncomfortable when worn for multiple hours at a time. So from there I bought a very cheap milanese loop knockoff for about $10 at Amazon. It’s very pretty, but had the same no-flex/no-give issues as the sports band.

In the end, I purchased a third party woven elastic band from Tefeca for just under $30 with tax shipped. I still don’t love having something physical on my wrists but this seems to be the best compromise I’ve found.

So what do you love about your watch and what advice do you have for me as a new watch owner? Please let me know.

UX fail: Logging into Apple TV

My son brought a new (which is to say, an old) Apple TV into our lives yesterday. He picked up a 2nd gen unit from Goodwill for under ten bucks in excellent condition. We were delighted.

Even older Apple TVs, a couple of generations before the app store hit, allow you to share music from the family library, watch shows and movies, project from hand-held devices, and use TVs as wireless extra displays.

We immediately began setting it up. The first issue at hand was to log into my Apple ID, so the unit could see my account, purchases, and home share.

I use long passwords. I recommend long passwords. Entering long passwords on a 2nd generation Apple TV using a remote is…well, it’s pretty horrible. Even though I’m a bit proud of my remote skills (for example, press-and-hold to access upper case letters from the lower case screen, or using hold-to-slide for quick letter navigation), it still takes a significant amount of time to enter my password.

And, when I had done so, and counted off the number of dots and confirmed they matched the right number of password characters, I expect that I was done with setup once I clicked the continue button.

Nope, not so quick.

It wasn’t until after Apple TV asked me whether to store my password for purchases (no thank you), and had moved onto yet another screen, that it stated I could not log in at this time. Something something about verification.

I assumed I entered the password wrong but I was a bit befuddled that it didn’t tell me that right away. I had already moved a couple of screens forward before it rejected my entry. What was going on?

After a few times through the process, I knuckled down and hit the web to search for “Apple TV verification”. That’s when I discovered that I needed to generate a verification code and add it to my password (one after the other, all in text in a single privacy-protected box) to log into my iTunes account.

This design shocked me. There was exactly no information listed on the enter password screen suggesting you need to not only enter your password but also append a six digit two-factor code to your password. There was no information guiding users through the steps to generate that code. There was no support for automatically sending a two-factor request to other registered devices, the way it normally works with my browser. Instead, you must generate a verification code on an another device using the same Apple ID.

I use two primary Apple IDs: one is for iTunes purchases and is shared with my family. The other is for my development work. All my mobile devices are signed into both, but you can only generate a verification code for your iCloud ID. You cannot for your iTunes ID.

I had to go through the hassle of picking a victim iDevice, logging out of iCloud, including disabling Find My iDevice and deleting all local iCloud data, just so I could log in using my iTunes account to generate my 6 digit time sensitive verification code. (Settings > iCloud > username > Passwords & Security > Get Verification Code)

It took me quite a bit of time to get a device to the point where I could do that. Wisely (but really just luckily), I left the device logged in to the iTunes iCloud account. I had not realized I’d need to authenticate in several places on Apple TV. The first time accessed my purchased content. The second time enabled home sharing. Again, without any hints about extended passwords and 2FA.

Fortunately, I targeted an aging iPod touch as my sacrificial victim, which, while running the latest iOS release, is not a heavily used dev system. I have not yet moved it back to my main iCloud account  just in case I have to go through this nonsense again.

Once I had my six digits, I had to add them to my password entry. Since timing is critical, I had to type out the password first, fetch the code, and then enter the verification code on my  Apple TV, which had gone into screen saver mode due to the delay. I added the digits to the end of the password (none of which are readable, it’s all dots), and hoped that it took.

All of this took place without any textual or visual indication to set user expectations that the password needed extra characters at the end to begin with.

This is probably the worst design for 2FA anyone could have come up with and I’m baffled at how this got past any level of management to be presented in Apple deployment. It feels like the first iteration of a solution offered by a summer intern before anyone with sense got involved.

I’d imagine that the second you enter an Apple ID, the device is fully capable of determining whether 2FA is needed. If so, it should guide the user how to obtain that information. Add some text, show a video, do whatever is needed, but contextualize!

Assuming that people know how to create the code and then append the code to the password is asinine. It’s also bad design. Make the 2FA code a second screen, for heaven’s sake. Lead users through the process. And for all that is good and holy, don’t make the user pass through one or more screens after the failed password before informing them that (1) the password didn’t take and (2) a validation step is needed and should have been done several screens earlier.

In the best of all worlds, just allow the 2FA code to auto generate and notify the way it does with Safari. Manual generation should be the fallback position only if associated devices are not available.

Every week or two, I have to re-enter a code to access Apple’s developer site. My office rings with the various beeps and whistles of 2FA. Every device helpfully shouts out its association with the iCloud account and provides a six digit key for me to use right away.

Having to laboriously set up a device and then manually generate a code is nonsense. Differentiating the main iCloud account and the iTunes account, both of which have been authenticated, is also nonsense. If a device is signed into both, it should produce 2FA codes for both.

The screen that most offended me was the one interspersed between the “enter your password” and “you need a verification code”. Who gave the okay to continue on with the “use this password to authorize purchases” screen before confirming 2FA? It’s just insane.

In the end, a process that should have taken 5 minutes max stretched to nearly 90. If someone comfortable with problem solving and web searches was this put off by the anti-intuitive UX design, imagine how Apple’s core customer base will react.

This is the furthest I’ve ever gotten from “it just works” in Apple’s ecosystem and a user experience that gives me great pause.

Teaching collections: shifting paradigms and breaking rules

Just because some things look alike and may act alike at some level, doesn’t mean that they should be taught at the same time, under a unified umbrella of learning. Consider bagels and donuts. They are both toroids . You can layer several instances onto a stick for storage or serving. You can cut them both in half. If you have no taste or sanity, you can place custard — or, cream cheese, salmon, onions, and capers — interchangeably between the two sides of either item.

Despite these common API surfaces, their use-cases, edge conditions, and recipes share little overlap. Conformance to ToroidFoodstuff does not correlate with each preparation of dough, the cooking process, or the serving and accoutrements associated with either food.

So why do we always have to lump arrays, sets, and dictionaries into a single lesson on collections?

A new language learner has little interest in traversing dictionaries, although it’s possible, or taking a set’s prefix, which is also allowed. Nor are new learners always prepared to take on optionals, the core return value for dictionary lookups, early in the language learning process.

I’ve recently spent some time helping to outline an introductory sequence for Swift learning. I pitched eliminating collections as a single topic unto itself. I want to reject superficial similarity and build language skills by introducing simple, achievable tasks that provide measurable and important wins early in the learning process.

Take arrays. They can store numbers and strings and more. You can grow them, shrink them, slice them. They have a count. They have indexes.  Arrays are perfectly matched with iteration in general and for-in loops in particular. Arrays and for-in iteration work hand-in-hand. So why not learn them together?

The answer is generally that arrays belong with collections and for loops belongs within a larger set of iteration topics. Ask yourself whether new coders actually need while and repeat-while loops in their initial approach to the language? How often in normal Swift coding do you reach for those two for simple reasons in simple code?

I’m not saying while-loops shouldn’t be taught. I’m trying to figure out what sequence of incremental learning provides new Swift developers with the most coherent set of basic tools they need to express themselves and expand their understanding over time.

Every classroom minute spent mastering while is a minute that could expand and practice for. Introductory lessons should focus on the core terms and patterns most commonly used in the workplace. Expressive language vocabulary can always be expanded through practice and engagement. Classroom minutes represent the restricted path.

Dictionaries, I argue, should be taught late. Every lookup is tied directly to optionals, a dictionary’s native return type. And optionals are quite a conceptually heavy topic. Dictionaries are the perfect pairing.  The type is a natural source of optional output, and an opportunity to discuss nil-coalescing and default fallbacks.

From there, you can pull in failable initializers, and optional chaining.  Dictionaries also lend themselves to advanced concepts like (key, value)-based for-in loop tuples, the key-value basics of Codable, and how custom structs relate to key-value coding, not to mention the entire conversation about nil, errors, try?, and more.

As for sets, well, I love sets and use sets, but are sets even appropriate for new learners outside of some sense of “completionism” learning? Should they be taught only because they’re one of the “big three” collection types? I’d argue that people should learn sets when they are already proficient in core language basics, not in the most introductory setting.

For example, you can tie sets into a lesson on view touches. Just because they’re a collection doesn’t mean that the newest students have to learn every collection right away, just as they don’t need to learn NSDictionary, NSArray, and AnyObject, and so forth, in the first days or weeks of exposure to Swift.

Trying to structure a plan to create a solid foundation of incremental learning is a challenging task for any non-trivial topic. When it comes to Swift and Cocoa/Cocoa Touch with its vast range of potential interests, ask the questions: “What core concepts and patterns best reward the language learner with immediate benefit?”, “What grouping conventions should be tossed overboard to better focus on the skills with highest returns?”, and “What critical paths allow learners to proceed towards measurable skills and performance with the least overhead?”

Justify each topic with an answer that’s not “it’s covered that way in the Swift Programming Language book”, especially when working with new learners versus developers moving into the language with existing programming experience. And even when teaching more experienced students, let the daily realities they’re trying to move towards mold the curriculum of what you choose to teach.

The best learners teach themselves. The best curriculum sets them up to do so.

Swift 5 gives us Nice Things™: Custom string delimiters

Say, for whatever reason, you were in desperate need of Bill the Cat ASCII art in your app. Maybe you were very drunk and had a bet. Maybe you were working with some kind of Unix awk client. I dunno. Let’s just start with the proposition that this was a real and meaningful challenge in your life.

In Swift 4.2, you could use multiline triple-quoted strings. Multiline strings are great for preserving indentation and other formatting, plus as a bonus, you get embedded quotes for free. Let me show you an example of how this works.

Instead of:

"\"I don't think...\"\n\"Then you shouldn't talk,\" said the Hatter."

with its multiple escape sequences, Swift 4.x gave us:

"""
    "I don't think..."
    "Then you shouldn't talk," said the Hatter.
    """

Same results, less fuss. The triple-quote string delimiter replaces the one-quote, so you don’t have to use backslash escaping. Dialog flows freely in 4.x.

But what happens when your source uses backslashes, as does this Bill the Cat clip art?

// error: invalid escape sequence in literal
let billTheCat = """
<------- ____
  &&&    /    \  __ _____,
    `-- |  o   \'  `  &&/
       `|      | o  },-'
         \____( )__/
         ,'    \'   \
 /~~~~~~|.      |   .}~~~\
  ,-----( .     |   .}--.
        | .    /\___/
         `----^,\ \
                \_/
"""

Nearly every backslash triggers a compiler error as an invalid escape sequence. The others are subsumed into an unintentionally valid escape (like \'). You have inadvertent line escaping at the ends of the seventh and eighth lines as well.

You have to escape each backslash, losing the ability to evaluate your clip art source at a glance. Every escape pushes characters on that line one item to the right. Given that this is Bill the Cat, not much is lost aesthetically speaking, but the results are less maintainable and harder to visualize.

let billTheCat = """
<------- ____
  &&&    /    \\  __ _____,
    `-- |  o   \\'  `  &&/
       `|      | o  },-'
         \\____( )__/
         ,'    \\'   \\
 /~~~~~~|.      |   .}~~~\\
  ,-----( .     |   .}--.
        | .    /\\___/
         `----^,\\ \\
                \\_/
"""

The problem becomes more pronounced when you work with pre-escaped material instead of visual art. For example, you may have escaped JSON or XML you want to paste directly into an app’s string. Each stringity escape sequence is an error waiting to happen:

{\r\n  \"first_name\": \"John\",\r\n  \"last_name\": \"Smith\",\r\n  \"is_alive\": true,\r\n  \"age\": 27,\r\n  \"spouse\": null\r\n}

Enter Swift 5. Its custom delimiters work on escape sequences the way that multiline strings work on dialog. Just add a pound sign (#) to each end of your string and your backslashes are perfectly preserved without hand edits or audits:

// Perfect Bill
let billTheCat = #"""
<------- ____
  &&&    /    \  __ _____,
    `-- |  o   \'  `  &&/
       `|      | o  },-'
         \____( )__/
         ,'    \'   \
 /~~~~~~|.      |   .}~~~\
  ,-----( .     |   .}--.
        | .    /\___/
         `----^,\ \
                \_/
"""#

Those extra pounds allow you to change the way Swift interprets escape sequences. They transform escapes from simple backslashes to \#. To insert a newline into a pound-delimited string, you type \#n and not \n. Similarly, string interpolation becomes \#(...interpolation...).

This system was inspired by the Rust programming language. Rust stacks one or more pounds at each end of a string (and prefixes the letter “r”) to create what it calls “raw strings”, that is strings without further escape sequence interpretation.  You cannot incorporate interpolation or coded tabs, new lines, or returns.

Swift adopts the extensible delimiters (skipping the ugly “r”) but retains its useful escapes, including string interpolation. Swift adapts each escape sequence to match the number of pound signs used at the start and end of the string. Instead of “raw strings”, Swift has, well, let’s call them “medium rare strings”. It allows you to paste and preserve raw formatting while retaining the ability to insert escape sequences.

In Swift 5, each of the following declares "Hello", even though they use a variety of single and multiline styles:

let u = "Hello" // No pounds
let v = #"Hello"# // One pound
let w = ####"Hello"#### // Many pounds
let x = "\("Hello")" // Interpolation
let y = #"\#("Hello")"# // Interpolation with pound
let z = """ // Multiline
    Hello
    """
let a = #""" // Multiline with pound
    Hello
    """#

Here are the rules:

  • You must match the number of #-signs before and after the string, from zero to however many. “One” is almost always the right answer for “however many”.
  • When you use #-signs, you change the escape sequence from a single backslash to a backslash infixed with the same number of pound signs. A ##"Hello"##  string uses the \## escape sequence.
  • Anything that doesn’t match the closing delimiter is part of the string. To add """ to a multiline string without escaping, just change the delimiter with pound.
  • Use the least number of pound signs required for the results you need. Zero is best. One is fine. Two or more is very, very rare.

And that’s it. With this one small change, anyone writing code generation apps like PaintCode or Kite Compositor (or one of my many utilities), writing network code with escaped-JSON,  or including weird Bill the Cat clip art, can paste and go. Just add pounds as needed, without sacrificing the convenience of string interpolation or escape sequences.

SE-0200, which introduces this new behavior, is one of my favorite proposals I’ve ever worked on. I’ve been lucky enough to have had a working toolchain with these features (thanks John H!) since before the proposal was even adopted.  I can’t wait until Swift 5 debuts, allowing custom string delimiters to become part of everyone’s coding work as well.

Musing on API names for trailing and functional closures

When a call returns a value, I almost always use in-line closures. I prefer to surround functional calls with parens. I know my style is not universally popular, as many developers prefer the look of raw braces. It’s not uncommon to see calls like this:

numbers.sorted { $0 < $1 }.forEach {
  print($0)
}

The functional sort is chained to the non-functional loop, both using braces. Mandatory functional parens do two things. They differentiate expressions and they add the clarity of role labels that are lost with trailing closures. Compare these with the preceding call:

numbers.sorted(by: { $0 < $1 }).forEach {
  print($0)
}

// or even

numbers.sorted(by: <).forEach { print($0) }

In each case, the combination of name and label (in this case, sorted(by:)) is clearer and more easily read. Many APIs are designed without initial labels for Void-returning closures. They’re intended from the start to act as language-like constructs, so adding labels is either superfluous or detracts from the call when omitted:

public func forEach(_ body: (Self.Element) throws -> Void) rethrows

Omitting labels shouldn’t cloud intent even when a closure meant for functional calls is used. I could imagine common API naming rules to help guide labels and functional use (for example, “omit labels for Void-returning closure arguments” or “include role hint labels for functional closure arguments used to process and pass through values”).

Such rules might help but there’s one class of closures that doesn’t normally follow. Completion handlers, especially those sourced from Cocoa and Cocoa Touch, are almost always labeled as completion or some close variant. They’re designed for non-returning (and often asynchronous) execution. For example, you might see:

func run(_ action: SKAction, completion block: @escaping () -> Void)

or

func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

These items are normally called as trailing closures, so why shouldn’t their API naming follow suit? Wouldn’t it make more sense to have _ completionBlock: or _ completionHandler: than to use explanatory labels that are most commonly hidden when called?

What do you think? Let me know.

ISO-8601, YYYY, yyyy, and why your year may be wrong

The end of the year is rolling around and it’s time to remind everyone about that yyyy works the way you think it does and YYYY does not. Here’s a quick example to start:

Just because you test a format quickly with the current date and get back the result you expect, does not mean you’ve constructed your date format correctly.

Speaking of which, BJ Homer points out that you can just use “y”, as “yyyy” pads to 4 digits which doesn’t usually matter but isn’t always needed. Olivier Halligon adds, further, that not all calendars use 4 digit years. “For example the Japanese start a new era every time the emperor changes, resetting to year 1 in that era; we’re currently in year Heisei 30.”

To quote The Dave™: “Nooooooo…. Please use “y”, not “yyyy”. “yyyy” zero-pads years that aren’t four digits, and there are multiple calendars w/ 2 or 3-digits years (Japanese, Chinese, Republic of China). “y” is the natural length of the year: “30” for Japanese cal, “2018” for Gregorian, etc”

What you’re actually seeing with “Dec 24, 2017” is the first day of the last full week of the preceding year. It doesn’t matter what numbers you plug into the month (“MM”) or day (“dd”). The presence of YYYY in the date format without its expected supporting information reduces to “start of year, go back one week, report the first day”. (I’ll explain this more in just a little bit.)

Here are some examples, which you can check from the command line using the cal utility:

As Apple’s 2014-era date formatting guide points out:

A common mistake is to use YYYY. yyyy specifies the calendar year whereas YYYY specifies the year (of “Week of Year”), used in the ISO year-week calendar. In most cases, yyyy and YYYY yield the same number, however they may be different. Typically you should use the calendar year.

Unicode.org’s Unicode Technical Standard #35, Date Format Patterns goes into a little more depth:

[“Y” is] Year (in “Week of Year” based calendars). This year designation is used in ISO year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems where week date processing is desired. May not always be the same value as calendar year.

ISO 8601 uses a 4-digit year (YYYY) for “week of year” calendars from 0000 to 9999. If you’re into trivia, the years before 1583 are technically excluded except by special agreement between sending and receiving parties.

Anyway, if you’re going to use YYYY formats, you’ll want to use additional format elements that support “week of year” date construction. For example, consider the calendar for this upcoming January, which starts on Tuesday the 1st:

    January 2019      
Su Mo Tu We Th Fr Sa  
       1  2  3  4  5  
 6  7  8  9 10 11 12  
13 14 15 16 17 18 19  
20 21 22 23 24 25 26  
27 28 29 30 31

This year, January first can be considered as the first week of 2019 or the 53rd week of 2018, as the weeks overlap in the middle. Using e (the numeric day of the week) and ww (the ordinal week to count from), you can represent both dates correctly using the oddball YYYY formatting token.

Here are examples that use the week-of-year approach counting from both 2018 and 2019:

As you can see from this, when you use YYYY and do not supply an ordinal week or day, they both default to zero, which is why you get the behavior of the zeroth week (that is, the week before the first week) on the zeroth day (also, the first day of that week) for that calendar year, which is the week before the first week that overlaps the stated year. This explains the results of all those otherwise random late-December dates from earlier.

ISO 8601 should be updated in a few months, with a release somewhere around February.

From what I can tell, the first part revises the current standard and the second expands it. The only freely accessible human-viewable material I could find were the five-page TOC previews for 8601-1 and 8601-2.

(Hat tip: Thanks, Robin Malhotra)