Archive for the ‘Development’ Category

“mint” (a simple SwiftPM installer) has improved my command line life

SwiftPM’s lack of an easy install feature has long been an issue of mine and for other people too. As the linked forums thread suggests, to accomplish this for a general audience requires some careful thinking: adding to /usr/local/bin is not always the best solution for every user.

Still, it’s a feature whose absence is notable. To fill the gap, I’ve discovered Yonas Kolb’s mint. Thank you to Leo Dion, who introduced this to me. It is ridiculously simple to use. Could it get easier than mint install erica/now? Admittedly my github id is short and so is my project name, but I think my point stands…

Yesterday, I hastily added a SwiftPM project to remind so it too could be installed via mint. Suddenly, adding the project specification is no longer an afterthought but a driving feature. It’s made SwiftPM support far more valuable to me for executables.

Make sure you name your primary file main.swift, your product to .executable, and if you’re developing in Xcode, override your path to point to the Xcode-project-style folder for the source files, usually the same name as the project itself. I mention this because Xcode by default (File > New > Swift Package) builds library projects, not executable ones. At the command-line use swift package init --type executable.

// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "remind",
    platforms: [
        .macOS(.v10_12)
    ],
    products: [
        .executable(
            name: "remind",
            targets: ["remind"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.6"),
    ],
    targets: [
        .target(
            name: "remind",
            dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")],
            path: "remind/"
        ),
    ],
    swiftLanguageVersions: [
        .v5
    ]
)

As for mint itself, you can build it or install it via HomeBrew: brew install mint.

If you have any suggestions on how I can improve my SwiftPM work, better integrate tagging, or any other tips, please let me know. Thanks!

Musings on `Result` and building a command line utility with completion handlers

Collaborating with Paul Hudson is a pleasure but the time difference can be, well, confusing. So when I started putting together an outline about the new command line argument parser for Pragmatic, one of the first things I wrote was a command line utility to tell me what time it was in Bath, UK:

% now bath uk
Bath 4:16:42 PM (GMT+1 United Kingdom Time)

I use CLGeocoder to use whatever terms I enter after the command as the hints to look up places of interests. I grab the first match and pull the time zone from that match (or throw an error if there’s no possible match).

Command-line utilities are not particularly well known for their asynchronous feature support. Because geocodeAddressString does run asynchronously, I use the quick and dirty trick of starting a runloop that executes until the completion handler finishes. I’m basically adapting an async method to sync.

This gave me an opportunity to finally get around to using the new Result type. Restrictions on other projects prevented me from kicking its wheels (or I was already using my own version from way back).

I struggled a little with how to incorporate Result. Here’s an earlier go at this. I use an optional resultto store the result, which is then set in completion scope:

var result: Result<[CLPlacemark], Error>?

CLGeocoder().geocodeAddressString(hint) { placemarks, error in
    switch (placemarks, error) {
    case (_, let error?):
        result = .failure(error)
    case (let placemarks?, _):
        result = .success(placemarks)
    default:
        fatalError("Geocoder error, no results.")
    }
    CFRunLoopStop(CFRunLoopGetCurrent())
}
CFRunLoopRun()

This code bothered me, and not just because I had to test and unwrap result when control returned to the main part of my method. It seems so obvious that Result should have a simple initializer based on the common elements found in legacy completion handlers. This would collapse those arguments to, for example, completion(Result(error, data)). Unless I’m missing something big here, I thought to build my own convenience initializer:

extension Result {
    init(_ success: Success?, _ failure: Failure?) {
        precondition(!(success == nil && failure == nil))
        switch (success, failure) {
        case (let success?, _):
            self = .success(success)
        case (_, .let failure?):
            self = .failure(failure)
        default:
            fatalError("Cannot initialize `Result` without success or failure")
        }
    }
}

That extension allowed me to collapse the code down to this. Notice how I can use the initializer here to eliminate the optional result, simplifying my extraction with get, towards the end. Admittedly, it’s not always easy to come up with an initial value that can be overwritten this way, but here it worked. The handler became two lines long, and processing the result to get my placemark (including all error handling), another two lines:

static func fetchPlaceMark(from hint: String) throws -> CLPlacemark {
    var result: Result<[CLPlacemark], Error> = Result([], nil)

    CLGeocoder().geocodeAddressString(hint) { placemarks, error in
        result = Result(placemarks, error)
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
    CFRunLoopRun()

    let placemarks = try result.get()
    return placemarks[0]
}

I quite like my initializer and wonder why something like that doesn’t already exist unlike init(catching:() -> Success). I’m curious as surely I’ve missed something important. Even in normal completion handlers, I’d imagine using the legacy Error? and Data? optionals would be a common use-case for Result

Let me know.

How to contribute to the iOS Developer Survey

Dave Verwer, bless his heart, put together an amazing collection of developer statistics in this year’s iOS developer survey. From careers to conferences, dev tools to frameworks, he profiled the community to discover what is happening on our platforms and in our jobs. If you haven’t already been over to the survey site, go and click the link. Don’t worry, this post will still be here when you get back.

The raw data only goes so far. What the survey needs now is you. Dave is looking for community members to help analyze the results so we can better understand what all this data means. For example, we’ve come to love and cherish our dev tools in a way that was unthinkable just a few years ago. Are the high marks for Xcode universal or are  coders with, say, five or more years of development experience particularly grateful for this advancement?

If you have an interest in deeper analysis, Dave has tools to help you slice, dice, and Julian fry the results. Right now there are just four articles available that evaluate the core information (“Is WWDC already a virtual conference?”, “How popular is Swift?”), and they’ve been written by Dave himself.

This data is crying out for deeper investigation, more voices, and diverse insights. If you have time and curiosity, I urge you to reach out to Dave on Twitter and get involved.

This is a fantastic opportunity to give a little back to the community that nurtures our professional lives.

How to fix: Ooops, I lost track of those beta upgrades

What happens when you put off beta upgrades and put them off and off and off and suddenly the release version has outpaced the beta? This happens:

And this happens:

So there you are, stuck in beta and complaining to your friends about what is, ultimate, my your fault. If you don’t update on a timely basis, you can waste a few hours (as I just did) getting your system back on track so you can mess with (for example, just to pull something out of thin air) Swift Playgrounds for iOS for Mac (which requires the 10.15.4 beta10.15.3).

Just so you don’t waste time, don’t try installing the 10.15.3 combo updater. (Image above) You need to:

  • Unenroll from the beta program,
  • Install the latest macos from the App Store,
  • Re-enroll into the beta program, and
  • Upgrade to the latest beta.

Prepare to waste your entire morning on this, hopefully less the time I spent figuring it out courtesy of friends. Once you get the App Store blessed macos install going, remember that once it reboots, there’s another hour of wait time just on the standard install:

Those 13 minutes are a lie.

Expect at least another hour once you get to the beta access installer:

Hopefully this post will help anyone doing a websearch to get out of exactly this issue at some point in the future.

A final note: Once you’re up to date, swear to yourself that your rule of “never be the first to install a new beta” doesn’t mean “never be the last to install the new beta“. Hopefully I’ve learned my lesson.

Circles within circles: custom types and extensions

So the other day Paul and I were shooting the breeze about spirographs. He was saying I needed to get back to blogging now that I have the time. Of course, the second you set out to try to write a post, so many ideas flow forth at once, it actually is hard to pick just one and focus on it. Since he had enjoyed my drawing work, I thought I’d start out with a little push at circles.

That quickly went out of control because I ended up with enough material for a few chapters rather than a single blog post. (And, no, my chapter for his book is about property wrappers, which I love, rather than drawing)

To give a little context, before I decided to try my hand at full time work, I had had a contract with Pragmatic to update my Drawing book. I had to cancel that because commuting full time to another city left me with zero free time for my self, my family, let alone writing. (Now that I am back at my own desk, I may see about returning to that project because geometry is a core passion.)

Anyway, let me start at the end of all this and show you some pictures and then I’ll (pardon me) circle back and start telling the story of the code and how all this came to pass.

I started my day by opening a playground, deciding to just flex my coding and see where it would take me. I wanted to work with circles, so I plugged a range into a map to get me there.

// Get some points around a circle
let points = (0 ..< nPoints).map({ idx -> CGPoint in
  let theta = CGFloat(idx) * (CGFloat.pi * 2 / CGFloat(nPoints))
  return CGPoint(x: r * cos(theta), y: r * sin(theta))
})

// Create a path
let path = UIBezierPath()

// Get the last point before the circle starts again
let lastIndex = points.index(before: points.endIndex)

// Draw something interesting
for (point, index) in zip(points, points.indices) {
  let p0 =  index == lastIndex
    ? points.startIndex
    : points.index(after: index)
  let p1 = index == points.startIndex
    ? lastIndex
    : points.index(before: index)
  path.move(to: .zero)
  path.addCurve(to: point, controlPoint1: points[p0], controlPoint2: points[p1])
  
}

It’s not the worst code in the world, but it’s not great. I was rewarded with a pretty path, so whee. Still, the code was screaming out that it wanted to be better.

I started by attacking the index work. Why not have an array that supported circular indexing by offering the next and previous items? So I built this:

public extension Array {
  /// Return the next element in a circular array
  subscript(progressing idx: Index) -> Element {
    idx == indices.index(before: indices.endIndex)
      ? self[indices.startIndex]
      : self[indices.index(after: idx)]
  }
  
  /// Return the previous element in a circular array
  subscript(regressing idx: Index) -> Element {
    idx == indices.startIndex
      ? self[indices.index(before: indices.endIndex)]
      : self[indices.index(before: idx)]
  }
}

Before you start yelling at me, I quickly realized that this was pretty pointless. Arrays use Int indexing and I had already written wrapping indices a billion times before. Just because I has the concept of a circle in my head didn’t mean that my array needed to. I pulled back and rewrote this to a variation of my wrap:

public extension Array {
  /// Return an offset element in a circular array
  subscript(offsetting idx: Index, by offset: Int) -> Element {
    return self[(((idx + offset) % count) + count) % count]
  }
}

Much shorter, a bit wordy, but you can offset in either direction for as far as you need to go. I did run into a few out of bounds errors before remembering that modulo can return negative values. I decided not to add in any assertions about whether idx was a valid index as arrays already trap on that, so a precondition or assertion was just overkill.

Next, I decided to design a PointCircle, a type made up of points in a circle. Although I initially assumed I’d want a struct, I soon realized that I preferred to be able to tweak a circle’s radius or center, so I moved it to a class instead:

/// A circle of points with a known center and radius
public class PointCircle {
  
  /// Points representing the circle
  public private(set) var points: [CGPoint] = []
  
  /// The number of points along the edge of the circle
  public var count: Int {
    didSet { setPoints() }
  }
  
  /// The circle radius
  public var radius: CGFloat {
    didSet { setPoints() }
  }
  
  /// The circle's center point
  public var center: CGPoint {
    didSet { setPoints() }
  }
  
  public init(count: Int, radius: CGFloat, center: CGPoint = .zero) {
    (self.count, self.radius, self.center) = (count, radius, center)
    setPoints()
  }

  /// Calculate the points based on the center, radius, and point count
  private func setPoints() {
    points = (0 ..< count).map({ idx -> CGPoint in
      let theta = CGFloat(idx) * (2 * CGFloat.pi / CGFloat(count))
      return CGPoint(x: center.x + radius * cos(theta), y: center.y + radius * sin(theta))
    })
  }
  
}

I added observers to each of the tweakable properties (the radius, point count, and center), so the circle points would update whenever these were changed. By the way, this is a great example of when not to use property wrappers. Wrappers establish behavioral declarations, which this is not. My circle uses the observers instead to maintain coherence of its internal state, not to modify, limit, or expand type side effects for any of these properties.

Now I could easily create a circle and play with its points:

let circle = PointCircle(count: 20, radius: 100)
let path = UIBezierPath()
for (point, index) in zip(circle.points, circle.points.indices) {
  path.move(to: circle.center)
  path.addCurve(to: point,
                controlPoint1: circle.points[offsetting: index, by: 1],
                controlPoint2: circle.points[offsetting: index, by: -1])
}

I decided not to add some kind of API for passing a 2-argument (point, index) closure to my circle instance. It doesn’t really add anything or make much sense to do that here. It wouldn’t produce much beyond a simple for-loop, and the point here is to build a Bezier path, not to “process” the circle points.

My goal was to build enough support to allow me to iterate through the points and reference adjacent (or further offset) points to build curves. This does the job quite nicely.

It didn’t feel quite finished though. I wanted to add a little extra because one of the things I often do with this kind of drawing is create stars and points and loops using offsets from the main radius, often interpolated between the main points on the circle’s edge. Because I had built such a simple class, adding an extension for this was a snap:

extension PointCircle {
  /// Returns an interpolated point after a given index.
  ///
  /// - Note: Cannot pass the existing radius as a default, which is why the greatest finite magnitude is used
  public func interpolatedPoint(after idx: Int, offsetBy offset: CGFloat = 0.5, radius r: CGFloat = .greatestFiniteMagnitude) -> CGPoint {
    let r = r == .greatestFiniteMagnitude ? self.radius : r
    let theta = (CGFloat(idx) + offset) * (2 * CGFloat.pi / CGFloat(count))
    return CGPoint(x: center.x + r * cos(theta), y: center.y + r * sin(theta))
  }
}

The most interesting thing about this is that you cannot use a type member to default a method argument, which is why I ended up defaulting it to `greatestFiniteMagnitude`. It seems to me that it would be a natural fit for the Swift language to allow that kind of defaulting. In this case, it would say: “If the caller doesn’t specify a radius, just use the one already defined by the instance.” What do you think? Is that too weird an ask?

To wrap up, here’s an example using the interpolation:

let path2 = UIBezierPath()
for (point, index) in zip(circle.points, circle.points.indices) {
  path2.move(to: point)
  path2.addCurve(to: circle.points[offsetting: index, by: 1],
                 controlPoint1: circle.interpolatedPoint(after: index, offsetBy: 0.33, radius: circle.radius * -2),
                 controlPoint2: circle.interpolatedPoint(after: index, offsetBy: 0.67, radius: circle.radius * -2))
}

All the shapes at the start of this post are created from this and the preceding loop by tweaking the curve parameters. What pretty results will you come up with? If you build something particularly lovely, please share. I’d love to see them!

Reading stdin on the fly

Shai Mishali asks, “Is there something like readLine that lets me read stdin as the user types instead of waiting for an entire line?” The readLine function waits until the user presses enter or otherwise recognizes EOF to process input.

A little web search led me to this SO post, which is  based on this example, using termios, the Unix API for terminal I/O. After looking through both posts, I built a RawMode type to support direct input based on that code because nothing makes me happier than messing with solutions to make them a little swiftier.

To use this, you fetch bytes until you catch an EOF. It’s interesting to test both direct keyboard entries as well as pasting complex emojis. As I was working on this on both 10.14 and 10.15, I was mildly startled when my initial test code stopped working when I moved to 10.14. UnicodeScalar does not offer a utf8 view until 10.15:

extension Unicode.Scalar {
  @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  @frozen
  public struct UTF8View {
    @inlinable
    internal init(value: Unicode.Scalar) {
      self.value = value
    }
    @usableFromInline
    internal var value: Unicode.Scalar
  }

  @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  @inlinable
  public var utf8: UTF8View { return UTF8View(value: self) }
}

So thank you, Swift team, for giving us that. It’s a nice addition to the language!

Anyway, if you have a different approach or you can see ways to improve my take further, drop a comment and let me know.

Whisky tango foxtrot: Xcode allows ObjC switch unindenting

This happened.

You might think I’m about to go off on some Swift rant (and trust me there is a Swift rant inside me waiting to emerge) but it’s the second checkbox that made my mind explode.

From:

To:

Who thought this was a good idea? I’ve never been a fan of left-aligned case in Swift although I embrace it as the standard. But in Objective-Freaking-C? As a standard Apple-blessed toggle in Xcode? No! Thrice no! The option enabling the choice is bad for Swift and worse for Objective-C.

Why is this option in there and why is it available for both languages? It would be best to, as Joe Groff put it, “let sloth naturally lead everyone to pick the default” given that the feature has been expressed in Xcode. Or better yet, file some bug reports for the broken feature.

Each language default reflects years (and decades) of language style consensus:

  • Swift: keyword-aligned.
  • Objective-C: “scope”-aligned.

This new choice in preferences is madness.

Talk me down from here, friends.

The knee-jerk else-clause

I’ve gotten into several heated discussions recently (I wouldn’t call them arguments or fights as no blows were exchanged and we departed as friends) about whether an if-statement should always include a balancing else clause in languages where it is not mandated by a ternary if form.

My feeling is a firm “no”.

Let me attempt to represent the opposing viewpoint. As far as I can tell, the “yes” faction believes that as proper diligence, an else clause should always be added to address both truth scenarios, even if the clause is populated with nothing other than a comment saying “this clause intentionally left blank”. It promotes a consistent inspection of all possible cases, on par with a switch statement requiring full coverage.

I firmly disagree. In my opinion, if-statements boil down to three scenarios:

  • Special CasingAction that applies solely to certain logic conditions, where the absence of those conditions has no effect in the logic. In such case, I recommend to skip the else. There’s no point to it as the flow of execution continues past the additional steps introduced by the if-statement. Adding an else statement removes the clarity of the step-by-step logic and reduces the weight of the special casing in understanding the code.
  • Either-Or: Separate actions of approximately equal weight that apply to both outcomes. If statements are naturally biased towards the positive clause. If both statements are weighted the same, consider refactoring to switch. Even if the switch is ordered (as it must be in some fasion), a switch-statement reduces the emphasis given to either outcome. If both cases are quite large, consider breaking out functionality to dedicated methods. Further, if the logic overlaps between both cases, consider localizing the conditions closer to the differences, even if the test may be applied several times.
  • One case complex, one case simple: Actions that are of disparate impact or weight, where one clause greatly exceeds the complexity of the other, I always place the more complex clause first when used in an if-statement to emphasize the positive path. At the same time, if the simple case is non-trivial, this is an opportunity to consider whether the logic should be broken up or refactored in some way. If an if-clause is so significantly big that it takes up the majority of a method implementation, perhaps you should be using early return for the lighter condition and promoting the more complex logic to the main method body. To me, a heavy complex if-clause usually signifies an opportunity to refactor.

Given these styles, I don’t see any reason, whether from code-reading clarity or a strict adherence to potential future expansion, to automatically include else-clauses as a mandatory part of a coding style. They add heaviness without real functionality and speak to a philosophy of form weighed over functionality. Code should be light, clear, and direct. Mandatory-else is none of those things.

Am I wrong? Go ahead, convince me otherwise. I’m listening.

My enemy the Minimap

The minimap is one of Xcode 11’s starring features. I know many people were excited for it at its debut but after months of exposure, I now just disable it in the Adjust Editor Options menu (the five horizontal lines of unequal width indicating the contents of the primary editor) and grab back that room on my screen:

I’ve spent some time recently considering exactly why it is I hate the minimap so much. It’s not just that it takes up valuable horizontal space (although to be honest, it’s mostly that). If it did a better job to help me navigate or conceptualize my code, I wouldn’t resent that space. Rather, I get little out of it and it’s a blurred colorful distracting mess for me.

In theory, the minimap is a specialized scrollbar for code. It highlights where are you with respect to the file. You hover the cursor over it to view tooltip details. Upon finding a section,  you can quickly jump to it. Hold the command key down and all the tooltips appear at once for a quick and actionable  overview. All contextual bookmarks are larger sized so technically “legible” although I can barely read them with my bad eyes.

I don’t care where I am physically inside my file, so the scope highlights don’t offer much. I care where I am conceptually. My jump bar gives me the same overview as the minimap (using the command key) without stealing screen space or distracting me with extra pointless blurry information.

What I am at a loss to figure out is how the minimap does that better than my beloved jump bar or why people prefer having the big jumble on-screen. As far as I can figure, the overview (whether jump bar or minimap command key) provides the most powerful tool because it relies on recognition of the details you’re looking for. But most of the minimap is designed around recall: where you are in the file, what the shape of your code is like, etc, which is a far weaker place for cognitive support.

So what am I missing? Why should I love the minimap? Please help me figure out what I am not understanding here and help me turn the minimap from an enemy to a friend.

Xcode: Basics of the four-block wonder

The official name is “Navigate to Related Items” but to me, it’s the four block wonder, a menu button that sits at the top left of the Xcode editor. With this menu, you can hop between file counterparts (for example, .m/.h, or .swift/generated interface, which is what a lot of people use it for). But there’s so much more.

Set the cursor on a type, and you can view or navigate its superclass, subclasses, or siblings, as well as the protocols, extensions, and categories it connects to. A single click navigates you to the interface or implementation in question:

Use the cursor to establish the context for the menu, otherwise you’ll only see a smaller subset menu options, such as recent files. The callers option shows you your clients, and callees the items your code is calling — all specific to the current cursor context.

One of my favorite tools in the four-block menu is Generated Interfaces, which allows you to view an item’s Swift interface or see how it translates to Objective-C. For example, if you use an obvious preposition label, the ObjC generated interface subsumes it into its selector:

With this, you don’t have to wonder if your selector is specified right and you don’t have to override the selector with objc. You just look up the definition and you’re good to call.

In addition to contextual helpers, the four-block lets you select recently viewed files and, when using version control, recent files that have been locally modified and not yet committed (basically the ones showing the “M”-for-modified).

The four little squares may be tiny but it is a powerful tool in your Xcode arsenal.

Update: Lilly reminds me that you can bind the related items menu. I have mine bound to ^1 but I don’t remember if that’s something I did or something that is default. If you want to add or change, visit Preferences > Key Bindings and search for “related”.