Archive for the ‘Tricks of the Trade’ Category

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)

Better table processing

Thanks to Andy Lester:

#! /bin/sh

# Process pasteboard contents to md table. Thanks, Andy Lester.
# Copy table from Numbers or other tab-delimited spreadsheet.
pbpaste | perl -le'$_=<>;&x;s/[^|]/-/g;&x;for(<>){&x}sub x{chomp;s/\t/|/g;print"|$_|";}' | pbcopy

# Done.
echo "Styled pasteboard to table"

Converting spreadsheet data to Markdown

I find it’s a lot easier to prepare a table with Numbers than by hand. I was using this today and thought I’d share the how-to.

Step 1: Select the material you want to table-ize.

Step 2: Paste it into text edit. Numbers uses tab delimiters (at least it does for me).

Step 3: Use find/replace to replace all tabs with a vertical pipe symbol (|). Copy any of your tabs to populate the find field.

Step 4: Use find/replace to replace all newlines with the sequence pipe symbol – newline -pipe symbol. Copy a newline from your text to the find field and in the replace field type |, then paste the newline again, and then type | again.

Step 5: Add pipe signs to the start and end of your file. Before:

After:

Step 6: Duplicate the first line and replace all text between bars with dashes:

Step 7: If you have an empty left-top-corner like I do, add at least 3 dashes to the 2nd line between the first set of pipes:

And you’re done.

Pushing the gist envelope: gists with pics and zips

People often don’t realize how powerful GitHub’s gist pasting service is. It’s more than just a “paste” site. Gist offers a full version control system extension to GitHub’s main site. I’ve been working on developing version control training materials and gist is a great way to introduce the fundamentals.

Many gist users know that the site offers you pushbutton convenience to paste one or more files. You can create open gists and “secret” ones hidden from public view. Gist also lets you fork, revise, and explore diffs between revisions.

For example, you can work in groups when writing. Collaborators can fork and make changes to offer content feedback. You can then use diffs to see what edits were made.

Here are some diffs from a recent Raw String proposal I worked on:

And this is the corresponding “rich diff”, which is slightly prettier:

And there’s a lot more you can do with gist. That’s because gists, as version control repositories, can be cloned to your computer, modified, and pushed back to GitHub. This means you can, for example, set up albums of pictures or host an easy-to-distribute zip file.

Each gist URL is a repository’s address:

git clone https://gist.github.com/erica/7cd24c6ab2f737735a9ab2b95628c549

As a gist’s owner, you have commit privileges, allowing you to edit your gist from your computer.

The command line enables you to add binary files that you can’t from the web interface. I grabbed a bunch of kitten pictures from Pexels and added them to my gist. A nice way to create simple albums:

If you click “Download ZIP” at the top right, GitHub zips up the repository contents (in this case five kitten PNGs) and copies them to your computer. This is not cloning; the zip file just stores the source files, not the full git repo.

It’s just as easy to host an archive file. When you have an Xcode project or playground that you need to share, Gist provides a great intermediate service alternative to iCloud or Dropbox. If you need privacy, use the “secret gist”  button when creating the gist.

This isn’t, of course, the end of what you can do with gists. Because each gist is a git repository, you can perform all the same commands you would in any git repo. Gist, of course, has a limited interface, so you won’t be able to, for example, switch between branches from the gist website. On the other hand, you can perform other tasks that don’t depend on a GitHub UI like listing diffs:

% git diff cb9271da5070f11602d3ab436a05fb9705409fd2
diff --git a/raw.md b/raw.md
index 8ed7306..ea4b5ed 100644
--- a/raw.md
+++ b/raw.md
@@ -104,9 +104,8 @@ Escaping hinders readability and interferes with inspection, especially in the l
 
 ### Candidates
 
-A good candidate for raw strings:
+A good candidate for raw strings is non-trivial and is burdened by escaping because it:
 
-* Is non-trivial.
 * Is obscured by escaping. Escaping actively harms code review and validation.
 * Is already escaped. Escaped material should not be pre-interpreted by the compiler.
 * Requires easy transport between source and code in both directions, whether for testing or just updating source.

I think GitHub’s gists are pretty awesome. And now, at least for me, they’ve gone from handy but mindless pastes to something really special.

Do you have a special way to use gists? I’d love to hear about unconventional ways to use this utility site to push boundaries and introduce new functionality. Drop a comment or an email and let me know.

Forcing Compiler Errors in Swift

Thanks to SE-0196, Swift 4.2 introduces #warning() and #error() compiler directives. These will allow you to incorporate diagnostic messages and emit errors during compilation. Here are some examples from the proposal, which has already been accepted and implemented:

#warning("this is incomplete")

#if MY_BUILD_CONFIG && MY_OTHER_BUILD_CONFIG
  #error("MY_BUILD_CONFIG and MY_OTHER_BUILD_CONFIG cannot both be set")
#endif

The #error example uses conditional compilation flags (set with a -D option) to check whether conflicting configurations have been established for the build.

I’ve already written extensively about my dislike for screaming snake case (THINGS_LIKE_THIS) in Swift. Inevitably, it seems, devs use screaming snake case for their conditional compilation flags, whether MY_BUILD_CONFIGMY_OTHER_BUILD_CONFIG, or DEBUG. Although an industry standard, it feels like a clash with Swift’s aesthetics.

I’ve also written about my proposal for detecting debug conditions without having to supply an explicit DEBUG condition flag, so I’ll also leave that topic to the side for now. You can click on the link for more.

Back to topic, Swift’s newly adopted #error and #warning directives represents a big step up from current practices, which often rely on run-time rather than compile-time feedback.

#if !DEBUG
fatalError("This code is incomplete. Please fix before release.")
#endif

The unindented style in this snippet is now Swift default, avoiding minor doom pyramids for conditional compilation blocks. Even unindented, surrounding code with those conditional blocks is vertically expansive and subjectively ugly. To counter this, some coders have come up with in-line ways to force compilation (not run-time) errors with minimal condition blocks and a more succinct point-of-use approach.

Here’s an example I discovered from John Estropia. (He, in turn, cribbed it from one of  his co-workers.) He uses conditional compilation to set a TODO or FIXME (or whatever) typealias then uses it in-line at points where a debug build should compile and release builds should error:

#if DEBUG 
internal typealias TODO<T> = T
#endif

print("Remove this later") as TODO

It’s clever. Scoping the TODO typealias to debug builds allows lines annotated with as TODO to throw errors during release builds. This ensures compile-time feedback at all points where a TODO cast is performed:

error: ManyWays.playground:5:31: error: use of undeclared type 'TODO'
print("Remove this later") as TODO

It’s not beautiful but it’s effective. It carries information about the call site location and the message you want to emit. If I were applying this hack, I’d probably build an actual todo function rather than using the casting-gotcha. In the following example, I went with an upper camel case name to make the call look more directive-y and less like a standard global function. However, I drew the line at snake case:

#if DEBUG
internal enum IssueLevel {
    case
    mildImportance,
    moderateImportance,
    highImportance,
    criticalImportance
}

internal func ToDo(_ level: IssueLevel, _ string: String) {}
#endif

// The point of use offers a compilation error,
// a note, and a priority level
ToDo(.highImportance, "Remove this later")

// error: ManyWays.playground:13:1: error: use of unresolved identifier 'ToDo'
// ToDo(.highImportance, "Remove this later")

The nicest bit is that toggling from debug compilation to release is completely automatic and centralized to a single #if check.  It’s a fascinating approach if adopted consistently and ensures that all compilation message notes like this must be resolved and removed before release.

Right now, Swift does not support a #message directive, which performs a similar tasks. As many shops treat warnings as errors, they cannot establish a nuanced distinction between the two. If #warning were a thing, you could use #message to issue exactly this kind of “fix me” feedback. A further refinement, #messageOrDie (or something like that, because naming is hard)  could message for debug builds and error for release, going by whether assert statements would or would not fire.

Dave DeLong offers another approach for structural project semantics. His introduces a Fatal type to provide runtime cues for common development outcomes including notImplemented(), unreachable(), and mustOverride(). Nothing says “you need to remember to implement this” better than a spectacular runtime crash that explains itself with full position and function context. Another cue, brilliantly named silenceXcode() allows you to add methods that you never intend to implement and which should error if ever called.

There’s still space in Swift for expanding this metadevelopment support. I wouldn’t mind seeing both approaches added to the language: one for compile time (like #messageOrDie) and another for run time (like Fatal‘s namespaced static error members).

What do you think of these? And what parts of the metadevelopment process (like macros) are still MIA for you in Swift? Let me know. I’m curious to hear what else could be better established to support your development.

 

Writing Swift: Adventures in Compiler Mods

Ever since Swift adopted the “implement first, propose second” rule, some contributors to the Swift Evolution process have felt sidelined and dropped out of the community. It’s frustrating having ideas for positive language changes and not being able to implement those changes.

Despite expertise in Swift and Objective-C (not to mention any number of other languages), they like me may not be proficient in C++ and Python, the core tools of Swift language implementation. To date, my code contributions to Swift have been extremely low level.

I think I fixed a comment, added a string, and maybe one or two other tiny tweaks. (I did work on the Changelog file a while back but that is written in Common Mark, and does not involve programming in the slightest.)

I’ve wanted to be able to build what I can dream. And I’ve slowly been diving into the compiler in recent months to see what it takes to build something new. With quite a lot of hand holding from John Holdsworth, I implemented a couple of build directives to test whether (1) asserts can fire and (2) a build is optimized.

What is Debug?

Answering “what does ‘debug’ mean?” was a harder question than I initially thought. Coming as I do from Xcode, where ‘debug’ means a scheme I select from within the IDE, it took a bit of thinking and advice to think about ‘debug’ from a platform independent viewpoint. After going back and forth on the Swift Evolution email list and later the forums, the consensus centered on the two tests I mentioned above: assertions and optimization.

For many projects, a typical debug build is unoptimized where asserts can fire. As projects move into the beta process, that mindset changes. Many in-house and beta builds meant for wider use need optimization.

The state of the art uses the custom conditional compilation flags set with -D . This approach decouples the meaning of ‘debug’ (or for most developers 'DEBUG') from anything in-language that can be decoupled from build settings and persist through source code. Assert configurations have their own flag, -assert-config <#value#>.

Introducing these two tests lets you align your not-for-release code to assert states and/or optimization states:

#if !configuration(optimized)
    // code for un-optimized builds only
#endif

#if configuration(assertsWillFire)
    // code where assertions can fire
#endif

The proof-of-concept implementation coupled with a proposal means I may be able to submit a more substantial and meaningful contribution to the language.

Going Solo

Pushing forward, I wanted to test myself and check whether I could make changes on my own, even if that solo journey was quite small. I started by attempting to build the #exit directive that was being discussed on the forums. This turned out to be a little more complicated than I was ready for.

Among other challenges, #exit may or may not be embedded in an #if build configuration test. Using #exit should allow all material up until that point to be compiled into the build while gracefully excluding all material after. I didn’t know how to check whether the directive was embedded in a condition and how to properly complete the condition (#endif) while discarding remaining text. It was, at my stage of the journey, a step too far.

I put my first attempt to the side and tried something else. I tried to push a scope using with(value) { }, so the material within the scope was native to value. That too proved too difficult without assistance although I am beginning to understand how Swift creates and manages its scope. It was a programming failure but a learning success.

Two projects abandoned, I knew I had to pick something very easy to work with. Although I would have loved to have picked up and run with Dave DeLong’s context pitch (which is discussed here) , I recognized that I needed to bite off something smaller first. So I decided to add a #dogcow token that produces the string value `”????????”` in source. How difficult could that be, right?

About five hours and edits to twenty-one files later, I had it working. Kind of. Because I ran into one of the many frequent headdesk situations that plague Swift compiler development. I had focused on my edits to the most recent repo without rebuilding the supporting tool suite.

Ninja Builds

A ninja build is a quick way to build just the compiler component. But at some point you can’t ninja your way into an entire working toolchain. I couldn’t test my changes until I rebuilt everything, a process that can take many many hours on my Mac:

% ./swift ~/Desktop/test.swift
:0: error: module file was created by an older version of the compiler; rebuild 'Swift' and try again: /Volumes/MusicAndData/BookWriting/LiveGithub/Apple/appleswift/build/Ninja-ReleaseAssert/swift-macosx-x86_64/lib/swift/macosx/x86_64/Swift.swiftmodule

Argh.

Building the compiler is not a quick thing. Even a ninja build is a non-trivial investment of time. So if you want to be completely honest, the total coding and build time a lot longer than just five hours. A lot longer.

Make sure you’ve updated your repo, incorporated the latest changes for swift and all of its support tools, and built them all before working on your branches. It will save you a lot of frustration.

Be aware that in the time it takes to create even a small project, you’ll probably be out of date with master. Hopefully this won’t affect your changes, and the files you think you’re patching are still the right files you should be patching.

Designing My Changes

The best way to add anything to the Swift compiler is to find some construct that has already been contributed and look through pull releases to discover what parts of the language they had touched.

That’s how I got started with my assertions/optimization revision. I looked at the recent canImport()pull, and targeted the seven files that involved. In the end, I only  needed to modify four files in total, excluding tests. It was a fairly “clean” and simple update.

To add #dogcow, again excluding tests, I had to change nearly two dozen files, most of them written in C++, a few using Python and Swift’s own gyb (aka “generate your boilerplate”) macros.

I’ve put up a gist that details my notes as I performed file edits. (I did have to make some further changes once I started testing.) Each group consists of a file name followed by my changes, with some context around them to make it easier to return to those parts of the file.

That’s followed by any relevant grep results that encouraged me to edit the file in question plus error messages from the compiler, of which there were a few, as I made several typos and forgot at times to add semicolons to the ends of lines. (Damn you semicolons! shakes fist) I put ### markers near the errors to make them easier to find in the notes.

As you walk through my notes, you’ll notice that I had to create a token (pound_dogcow), which is a kind of MagicIdentifierLiteralExpr expression. By inserting a simple token without arguments and returning a string, I cut down on my need to parse additional components or produce a complicated return value.

(Sorry Dave! I’ll get there I hope… After all, I know where each of the five components of Context live: file, line, column, function, and dsohandle. I just don’t know how to build and export the struct so that it gets put into place and can be consumed by the Swift user.)

As a string, my #dogcow can be used as a literal, so I conformed it to KnownProtocolKind::ExpressibleByStringLiteral. It needed to be serialized and deserialized, emit its custom string, support code completion, and more. Scrolling down my file, you’ll see the scope of notes including searches, comments, and edits for this one change.

Debugging

One of the most interesting things that happened during this exercise was when I made an actual logic error, not a syntax error, so Swift compiled but my program failed:

Assertion failed: (isString() && "Magic identifier literal has non-string encoding"), function setStringEncoding, file /Users/ericasadun/github/Apple/appleswift/swift/include/swift/AST/Expr.h, line 1052.

For the longest time I was convinced (wrongly) that because I was using Unicode, that I had somehow screwed up the string encoding. This was actually a coding mistake, an actual bug, and had nothing to do with the way my string was built nor the fact that I used emojis. It took a while to track down because my head was in the wrong place.

Notice I have DogCow returning true here. I accidentally swapped the two lines so it was originally returning false, falling into the Line/Column/DSOHandle case.

 bool isString() const {
   switch (getKind()) {
    case File:
    case Function:
    case DogCow: // it's a string!
      return true;
    // it should not have been down here
    case Line:
    case Column:
    case DSOHandle:
      return false;
  }
  llvm_unreachable("bad Kind");

Proof-of-Concept

Once compiled, I used a few simple calls to test my work. Here’s the source code I used. I accidentally added an extra space in the assignment test. You can see in the screenshot as well:

// String interpolation and default argument
func hello(_ greetedParty: String = #dogcow) {
    print("Hello \(greetedParty)")
}

hello()
hello("there")

// Use in assignment
let aDogCow = #dogcow
print("The value is ", aDogCow)

// Use directly in statement
print(#dogcow)

Lessons Learned

Having built a working version of the compiler incorporating my solo changes, no matter how trivial and yes it was extremely trivial, has been a big confidence builder. Exploring the process from consuming tokens to emitting intermediate language representations has enlightening.

  • I learned to update everything and build from scratch before starting my work. Because if you don’t, you’ll end up doing it later and wasting that time.
  • I learned how to track down similar modifications and use them as a template for exploring what parts of the compiler each change touched.
  • I learned that some errors would not be in the compilation but in the testing, as one tends to forget things like “just because it built doesn’t mean it will compile correctly” when one is very very focused on getting things to run and extremely new to the process.

I have now worked on two (technically three) compiler modification projects. Each has  taught me something new. If you’d like, take a peek at some explorations I’ve pushed to my forked repo:

The DogCow changes are clean, in the style of something that I might actually do a pull request for. The optimization checks are not. They retain all my little in-line notes I use for searching through text files to find what I’ve changed.

The early debug checks represent the time before I could get all the compiler tools built on my system. I was basically programming in my head at that point, guessing what would work or not, before the conversation on Swift forums moved me to my current design.

My guesswork was wrong. I focused on using a trio of built-in functions (like _isDebugAssertConfiguration) mentioned on-list. This turned out to be a non-viable solution. I needed to follow the example set by canImport to set my flags.

Finally, a word to the wise: Don’t ./utils/build-script -R in one terminal window and ninja swift in another at the same time. Oops.

Cleaning up doc comments for formatted commits

I’m working on a proposal to introduce CountedSet, cousin to NSCountedSet, to Swift. This kind of type involves a massive amount of doc comment content. I decided to adapt the comments from Cocoa Foundation (for NSCountedSet) and Swift Foundation (for Set) as part of my coding and quickly found how ridiculous it was to do this by hand.

At first I tried to write an Xcode “reflow doc comments” extension but as I found in the past, Xcode extensions are a dreadful pain to program and debug. It really wasn’t worth doing this (although it would be my preferred workflow for use) in terms of spending my time well.

Instead, I decided to create a simple playground. I’d paste my Swift file into a known Resources file (in this case, test.swift, although I’m sure you can come up with a better name than that if you use this). I’d process the text with a simple playground implementation and print to stdout.

It was an interesting problem to solve and one that took slightly longer than I anticipated. It’s also one that’s only partially complete. The log jams involved looking ahead at the next line to decide when each blob of text was complete so it could be reflowed, preserving paragraph breaks in the comments, respecting code blocks, and leaving any in-file code intact. Reflowing the words was much easier. I’m sure you’ve written that part of it in any number of algorithms and intro-language classes.

The parts I didn’t tackle were the special formatting required for doc comment keywords, like - Parameter, - Returns, - SeeAlso, and so forth. The associated lines for these items must be reflowed with proper indentation so the Quick Help parser can properly parse them. I leave that for another day because they are relatively minor work compared to reflowing long and complex doc comments as a whole.

I’ve put my code up on Github if you want to offer improvements, fixes, or feedback:

 

Pattern match style filtering

I’ve written about this before, but a question came up recently that I thought was worth posting, as it’s a much simpler case than the one I wrote about last year.

Byrre_b asks:

Is there any way to write “pattern matching style filtering” in a better way then using a complete `if case` statement?

Such as:

let values: [NonEquatableEnum] = [...]
let filtered = values.filter { val in
    if case .thatOneInterestingValue = val {
        return true
    }
    return false
}

Note: Several people have pointed out if the enumeration is equatable, just use == rather than pattern matching. You can match case, even with associated values with, e.g. if case .foo = value.

You can filter using the pattern match operator, as shown here, or for equatable enumerations with ==.

enum NonEquatableEnum { case nah, blah, thatOneInterestingValue }

let values: [NonEquatableEnum] = [.nah, .blah, .nah, .thatOneInterestingValue, .nah, .thatOneInterestingValue, .blah]
let filtered = values.filter({ $0 ~= .thatOneInterestingValue })

Although this stores all values matching your subject case into filtered, the results aren’t very meaningful unless you want to count how many instances of .thatOneInterestingValue appear. That’s because filtering by enumeration case is usually limited to two situations:

  • You’re working with a structure and using the enumeration as a tag for filtering
  • You’re working with associated values and want to collect the enumeration cases and then extract the values.

The first of these is made simple with Swift 4 key paths. For example, consider the following structure:

struct Foo {
    var (x, y, z) = (0, 0, 0)
    let numnum: NonEquatableEnum
    init(_ n: NonEquatableEnum) { self.numnum = n }
}

let values2: [Foo] = [Foo(.nah), Foo(.blah), Foo(.nah), Foo(.thatOneInterestingValue), Foo(.nah), Foo(.thatOneInterestingValue), Foo(.blah)]

Assuming each instance has some more interesting data than the default (0, 0, 0) triple, pull out tagged instances using the same filter approach:

let kp = \Foo.numnum
let filtered2 = values2.filter({ $0[keyPath: kp] ~= .thatOneInterestingValue })

The key path lets you “dive” into each struct to test the enumeration member, while preserving the data stored in the other structure members. Instead of just counting how many instances of a simple enumeration there are, it acts as a meaningful filtering operation.

The second challenge, retrieving associated values, is more complex, as explained in my original write-up. Hand-crafting a result with if case gets you the values you need.

enum MoreComplicated {
    case one(Int)
    case two(Int)
    case three(String, String)
}

let values3: [MoreComplicated] = [.one(3), .two(5), .two(2), .three("hi", "there")]

Here’s an example that pulls out the case three enumerations:

let results2 = values3.filter({
    if case .three = $0 { return true } else { return false }
})

If you want to filter and extract at the same time,  add let declarations into your if case statement and switch the filter operation to a flatMap :

let results3 = values3.flatMap({
    (value: MoreComplicated) -> (String, String)? in 
        guard case .three(let x, let y) = value
            else { return nil }
        return (x, y)
    })

This returns an array of tuples, containing the associated values for each matching enumeration case.

Thoughts? Improvements? Fixes? Drop a note, tweet, or email to let me know!

How to check your security update

A macOS Security flaw opened access to users who didn’t have root passwords. So Apple updated computers overnight

Unfortunately Security Update 2017-001 turned out to bork file sharing, so Apple updated the problem both by issuing repair instructions and updating the patch.

To check whether you have the proper build, choose Apple Menu () > About This Mac. Click the System Report button and scroll down to Software. Click the word Software. You should be running 17B1003.

Thanks everyone.

p.s. Esopus Spitzenburg is my Mac mini. My MBP is Broxwood Foxwhelp. And yes, I’ve long since gone past Fuji, Gala, Rome, Honeycrisp, Pippin, Winter Banana, and many other varietals.