TODO.swift

I saw this Swift trick a few years ago on Twitter. I can’t recall who it was, sorry. It sounded way too clever at first, but after a while I tried and decided I love it. Now it’s one of those things I add to every project.

Sometimes you just want to get on with declaring your functions without worrying about the actual implementations. A small enough function with good enough name and types is pretty much done. Filling out the body is just something that will distract you and make you lose the big picture by bogging you down in the details.

The problem with incomplete functions is that they make the type checker unhappy. Have a return type but no return statement? That’s a compilation error. And the more interesting your types, the harder it is to make a temporary hack to placate the compiler.

Swift offers an escape hatch: the Never type. Call a function that returns Never and you don’t need to worry about writing a return. So this will compile:

func foo(zap: Bar) -> Fnord {
    fatalError("Unimplemented")
}

The code will compile, it will just crash at run time. Exactly what we wanted. But we can do better.

You can write your own function that returns Never as long as you ensure it never returns. Like, for example, by calling fatalError as we did in the previous example:

func TODO() -> Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO()
}

That’s an clear improvement: less need for repeating yourself, and easier to find in the code. The next small step will be to ditch the parentheses by switching to a computed property:

var TODO: Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO
}

Not a huge improvement, but better, anyway.

There’s one more thing we can do: we can make it harder to forget these in the code. TODO doesn’t cause errors, but we can make it cause a warning by abusing Swift’s deprecation annotation. And because you care for the quality of your code base you fix all warnings and so can’t help but notice the new ones when you compile.

@available(*, deprecated, message: "Unimplemented")
var TODO: Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO
}

Now the TODO line inside Foo will cause a warning:

'TODO' is deprecated: Not implemented

You’ll get a nice warning reminding you to implement the function before merging your code in, but you can do it when you’re ready.

Article page

Converting UNIX dates to a readable format on Mac

I tend to run into UNIX dates — large numbers representing points in time as seconds since the first second of 1970, something like 1500000000 for 2017-07-14 05:40:00 — all the time in my work, dealing with servers, web APIs, etc.

Here's how to make them readable on a Mac. All text below assumes macOS 10.13.

Terminal

The most straightforward solution is probably to open Terminal.app and run date:

# Outputs Fri Jul 14 05:40:00 EEST 2017
date -r 1500000000

# Outputs 2017-07-14 05:40:00
date -r 1500000000 +'%F %T'

Services: shell + AppleScript

Command line isn't your only option. macOS has a Services menu where you can add all sorts of useful things that operate on your selection:

Services menu screenshot

You can create a Service menu item pretty easily from the date invocation above.

  1. Launch Automator
  2. Create a new document. Select Service when Automator prompts for a type.
  3. Add "Run Shell Script" action. Select /bin/sh as the shell. Set the following as the content:

    sh xargs -I INPUT date -r INPUT +'%F %T'

  4. Add a "Run AppleScript" action. Set the following as the content:

    applescript on run {input, parameters} tell me to display dialog input with title "Date" buttons "OK" return input end run 5. Save the document, select text anywhere, select the \<Program Name> → Services → \<Your Automator document name> menu item, and you'll get a dialog box with the converted date.

Services: Javascript

Starting a shell, invoking (with no input validation) a couple of command line tools, then piping that to AppleScript is not very satisfactory.

You might be able to eliminate the first step and do all of it in AppleScript. But that would mean writing more AppleScript. I prefer to avoid that.

macOS offers another option: JavaScript for Automation, also known as JXA. Not exactly the greatest of languages either, but it's not as read only as AppleScript. And while its standard library is not great, it can handle dates. So we can reduce our Automator script to one action and improve our input validation at the same time.

  1. Start by again creating a new service in Automator.
  2. Add a "Run JavaScript" action. Set the following as content:

    ```javascript function run(input, parameters) { const app = Application.currentApplication(); app.includeStandardAdditions = true;

    const inputInt = parseInt(input);
    if (isNaN(inputInt)) {
        app.displayAlert("Not an integer: " + input);
        return input;
    }
    
    const d = new Date(inputInt * 1000);
    
    app.displayDialog(d.toISOString(), {
        withTitle: "Date",
        buttons: ["Close"],
        defaultButton: "Close",
    });
    
    return input;
    

    } ```

  3. Now again save the document. The new service is available in the Services menu.

Here's the window you get:

Date dialog screenshot

The output from toISOString isn't quite as nice as %F %T from date, but if you're used to ISO dates, it's not bad. Making it prettier is left as an exercise to the reader. Start with Mozilla's documentation for Date.

There you have it! Maybe some day we can use Swift and the Foundation libraries for automation, but meanwhile I can live with the JS solution.

Article page

Netstrings for Swift

I published another small Swift library: swift-netstring implements reader and writer for D. J. Bernstein's Netstrings format in Swift.

Netstrings is a specification for length-prefixed and delimited byte strings, useful mostly as a low-level building block for network protocols. With swift-netsring you can parse incoming data from a socket or some other stream by wrapping the stream in a simple closure that reads bytes synchronously. Or you can feed it an array of bytes.

You can find examples in the repo in the README, in a Swift playground and in tests. There's also API documentation (a big thank you to Jesse Squires for an excellent guide for setting up docs on GitHub pages for a Swift project.)

Article page

Flue: Fluent API for value extraction and conversion for Swift

Flue is a Swift (3.0, as of this writing) library for extracting, validating and converting values from user input. It tries to do this with a fluent interface:

vp.extract("100").maxLength(6).regexp("1.*")!.asInt().required()

It can output readable help and error messages from your conversions. See the README for details.

Enjoy.

Article page

Talking to servers: WebSockets

This is a sort of follow-up post to ZeroMQ, iOS and Python from a year ago. I again wrote a test app and server. Of the earlier components, iOS stayed, but ZeroMQ I replaced with WebSockets and the server is this time written in Clojure.

Idea of the exercise is the same as last time: two-way communication between an iOS client and server over a persistent connection. WebSockets is a more mainstream technology than ZeroMQ with a wide variety of servers available, even if it is a young spec and not quite everything has stabilized yet.

On the iOS side there's two options, short of writing the protocol implementation yourself: some kind of horrible Javascript-UIWebView bridge and Square's SocketRocket. I went for SocketRocket. It's available from CocoaPods and at least in this brief test worked fine.

Last time I was planning on doing the server in Clojure but ran out of patience. This time the technology stack was easier. I pretty much followed Jay Fields' example with just a few changes here and there and had a server running in no time.

The system doesn't do anything fancy, or do it particularly beautifully: the app waits for a button tap, sends a number wrapped in JSON to the server, the server increments it and sends it back.

The code is on BitBucket as always. Enjoy.

Article page

NSStringinfying enums from AppCode

I added a --text option to nsstringfromenumgen so it can be used with JetBrains' excellent Objective-C IDE, AppCode. AppCode doesn't integrate with OS X services, but you can configure nsstringfromenumgen as an "External Tool" and provide the selected text as a parameter. There's still an extra copy & paste step not needed with Xcode and Services, but it's not too bad.

Article page