Archive for the ‘Swift’ Category

Swift Holy Wars: To bracket or not in option sets?

As much as I’d like OptionSets to be a type, they’re not.

public protocol OptionSet : SetAlgebra, RawRepresentable

The current implementation (via a protocol), enables API evolution. As Joe Groff pointed out to me, developers can break down a single option into multiple refined options, while still offering the original components. You can see an example of this in the following implementation, where the compound energyStar and gentleStar  options occupy an equal footing with  component bit-shifted flags:

public struct LaundryOptions: OptionSet {
    public static let lowWater = LaundryOptions(rawValue: 1 << 0)
    public static let lowHeat = LaundryOptions(rawValue: 1 << 1)
    public static let gentleCycle = LaundryOptions(rawValue: 1 << 2)
    public static let tumbleDry = LaundryOptions(rawValue: 1 << 3)
    
    public static let energyStar: LaundryOptions = [.lowWater, .lowHeat]
    public static let gentleStar: LaundryOptions = [.energyStar, .gentleCycle]
    
    public init(rawValue: Int) {
        self.rawValue = rawValue
    }
    public var rawValue: Int
}

Although this design looks like you are using sets, you really aren’t.  The square bracket syntax is a bit a of a cheat:

let options1: LaundryOptions = [.lowWater, .lowHeat]
let options2: LaundryOptions = .energyStar
let options3: LaundryOptions = [.energyStar, .lowHeat]

// prints 3 for each one
[options1, options2, options3].forEach {
    print($0.rawValue)
}

When you surround an option set with brackets, you get back an option set. This means in Swift, [.foo] is the same as .foo.

I entered into a heated style debate today with Soroush Khanlou over option sets, specifically if it were better to make a call like accessQueue.sync(flags: [.barrier]) using or omitting the brackets.

Soroush felt that omitting the brackets produces less noise. If you can compile without the brackets, why include them?

I said “use ’em”. When you’re passing flags and a static member, let the role guide your style. When the code expects an option set, make the argument look like an option set.

The brackets clearly indicate both the argument role and creates an affordance, a specific visual indication that you can expand the set by introducing more options. Without brackets, this may not be intuitively obvious to someone less familiar with option sets.

So what do you think? Brackets? No brackets? What Swift cuisine reigns supreme?

Holy Wars: Namespacing Hygiene

sssilver writes: “In my company I find code that’s basically a class with a bunch of static functions in it. When I ask people why not just write the functions directly, they answer that they don’t wanna pollute the namespace. In something like Rust, everything is scoped to the module. What’s the idiomatic way to do this in Swift?

Swift prefers namespacing to freestanding functions and constants. This applies even in module APIs where you gain a basic level of namespacing for free. You want to keep your namespace clean and focused, scoping items to types and protocols of natural interest.

This practice makes Swift a bit more hierarchical than you might be used to. In Swift prefer to:

  • Namespace constants into a type where they naturally fit.
  • Namespace functions into the types and protocols they service, either as static methods or by removing the first argument and re-implementing the function as an instance method.
  • Add subtypes rather than pollute the global namespace with items that are only of interest within a parent type. Subtypes allow the parent and its nested types to reduce complexity when referring to each other, so Shape.Triangle and Shape.Circle see each other as Triangle and Circle.
  • Embed functions that will only be called by a single method client into that method, rather than create a second method that exists only to serve one parent.
  • Move operator implementations into the types they service, so you reduce the number of operators implemented in the global namespace.

Where you might have previously created public constants and functions like these, now prefer to incorporate them into existing or utility types:

public let π = CGFloat(Double.pi) // no
public let τ = π * 2.0 // no

public func halt() { // no
    PlaygroundPage.current.finishExecution()
}

extension CGFloat { 
    /// The pi constant, yes
    public static let (pi, π) = (CGFloat(Double.pi), CGFloat(Double.pi))
 
    /// The tau constant, yes
    public static let (tau, τ) = (2 * pi, 2 * pi)
}

extension PlaygroundPage {
    // This is never going to be beautiful
    public static func halt() {
        current.finishExecution()
    }
}

Embedding globals into types as static members provides clean, Swiftier namespacing, with minimal overhead costs. Where possible, prefer extending an Apple-supplied type (like `CGFloat` and `PlaygroundPage`) over creating new types (like `MathConstants` or `PlaygroundRuntimeSupport`).

At the same time, don’t force constants and functions into classes where they have no natural fit. If you must create a new type to warehouse a namespace, prefer a no-case enumeration, which is guaranteed to be unconstructable.

I’ll probably think of more things after I hit “Publish” on this, so if I missed anything, let me know and I’ll update the post.

 

Flybbertigybbets

“gyb” stands for “Generate Your Boilerplate”. Built in Python, it’s part of Swift’s utility suite. You can find its implemention here. It’s part of the open source Swift source.

Gybbing provides a preprocessor that automates inherently repetitive coding tasks. For example, it helps construct built in math types. With gybs, you don’t have to re-implement a common task for each type. That can get very old very fast. (Copying and pasting nearly-identical code is never fun.)

If you hop over to the standard library source, you’ll find a couple of dozen gyb sources to look at. These range from tuples to string interpolation to integers. They use a mix of GYB markup and injected Python code to generate related-type code.

Here’s the help info from running gyb -h:

usage: gyb [-h] [-D NAME=VALUE] [-o TARGET] [--test] [--verbose-test] [--dump]
           [--line-directive LINE_DIRECTIVE]
           [file]

Generate Your Boilerplate!

positional arguments:
  file                  Path to GYB template file (defaults to stdin)

optional arguments:
  -h, --help            show this help message and exit
  -D NAME=VALUE         Bindings to be set in the template's execution context
  -o TARGET             Output file (defaults to stdout)
  --test                Run a self-test
  --verbose-test        Run a verbose self-test
  --dump                Dump the parsed template to stdout
  --line-directive LINE_DIRECTIVE
                        Line directive prefix; empty => no line markers

    A GYB template consists of the following elements:

      - Literal text which is inserted directly into the output

      - %% or $$ in literal text, which insert literal '%' and '$'
        symbols respectively.

      - Substitutions of the form ${}.  The Python
        expression is converted to a string and the result is inserted
        into the output.

      - Python code delimited by %{...}%.  Typically used to inject
        definitions (functions, classes, variable bindings) into the
        evaluation context of the template.  Common indentation is
        stripped, so you can add as much indentation to the beginning
        of this code as you like

      - Lines beginning with optional whitespace followed by a single
        '%' and Python code.  %-lines allow you to nest other
        constructs inside them.  To close a level of nesting, use the
        "%end" construct.

      - Lines beginning with optional whitespace and followed by a
        single '%' and the token "end", which close open constructs in
        %-lines.

    Example template:

          - Hello -
        %{
             x = 42
             def succ(a):
                 return a+1
        }%

        I can assure you that ${x} < ${succ(x)} % if int(y) > 7:
        %    for i in range(3):
        y is greater than seven!
        %    end
        % else:
        y is less than or equal to seven
        % end

          - The End. -

    When run with "gyb -Dy=9", the output is

          - Hello -

        I can assure you that 42 < 43

        y is greater than seven!
        y is greater than seven!
        y is greater than seven!

          - The End. -

Defer; defer; defer

Someone was asking about defer, and the order in which they’re added to the stack. It’s pretty easy to create a test set-up like this one so you can play with them yourself.

Here are a few inspirational ways to use defer:

Pair tear-down tasks with setup. For example, if you’re deploying to pre-iOS 10, you might use begin and end for image contexts. Defer is also great for alloc/dealloc, fopen/fclose, etc.

UIGraphicsBeginImageContext(size); defer { UIGraphicsEndImageContext() }

Postdecrement/postincrement. Use defer to return a value before modifying it:

defer { x = x - 1 }; return x // x--

Apply “next state” updates. Use defer in sequence calls, like this example that repeatedly circles through the color wheel:

return sequence(state: hue, next: {
     (state : inout CGFloat) -> Color? in
     defer { state = state + stepAngle }
     ...
     return value }

Leverage group layout. This example draws an array of images into a line. The actual code does a lot of fussy work. Moving defer to the start of the forEach loop helps keep track of the “next step” without searching through the actual layout code.

allImages.forEach { image in
    defer { px += image.size.width + spaceOffset }
    image.draw(at: CGPoint(x: px, y: py))
}

Handy, no?

A few interesting things about iOS Swift Playgrounds

Misc rambles:

Interesting: You no longer “print” in iOS Swift Playgrounds. Anything that can be presented using a playground QuickLook or a custom string representation is done so with the tap-to-view item at the right. There’s no “printing” per se, no console, while I suppose you can import Foundation and NSLog stuff, I’m not sure how reasonable a solution that is, especially on the go.

Because: This morning I ended up importing AVFoundation to let AVSpeechSynthesizer “speak” feedback to me. Not ideal, but short and easy to implement, and got the job done for some stuff that wasn’t rendering nicely the way I needed it to, in a complicated playground book that was using SceneKit not UIKit.

Rad discovery of the day: Command-R runs the playground without having to tap the screen. \o/ Press and hold Command key (on a physical Bluetooth keyboard, this doesn’t work on, for example, type2phone) to discover other shortcuts:

screen-shot-2016-11-11-at-3-13-29-pm

Sad discovery of the day: You cannot air drop playground books anymore, and Swift Playgrounds is being very very careful about allowing you access to any material you didn’t create or import yourself. There’s no Documents support for iTunes. At the suggestion of Jonathan Penn, I gave it a try after rebooting and now it works. You wouldn’t believe how much time I wasted trying to extract information to look up implementation details.

Thanks again to Jonathan P for pointing me to the command-key discovery feature!

Swift By Emoji: A considered approach

Not too long ago Iain Delaney pointed me to this graphic:

cwniukiukaaydtj

The graphic was designed by Steve Luscher and written about by Joey Devilla in this blog post on Global Nerdy. I thought it was brilliant and inspiring.

It wasn’t written in Swift and certainly wasn’t running in Swift. I decided to play around: I built a playground, assigning massive lists of emoji strings to emoji variables, and got these examples running properly using Swift syntax.

mapfilterreduce2

Rather than use a pile of poo, which assumes at each stage of reduction you’re combining poo with a new food, I went with Jaden Geller’s recommendation on Twitter. In the Swift version, the reduction starts with a sad face and becomes happy and satisfied.

I played around with other foods to see if it was worth expanding the samples but it was never quite as clean or elegant as the simple 4-item original:

mapfilterreduce1

Stepping away from the cow/potato/chicken/corn space, I wanted to see if there might be a better filter than isVegetarian. A child makes amusing (if not nutritious) food choices:

filter

And then I thought, well what about other Swift language essentials. So I mocked up the concept of naming items by whether they are mutating or non-mutating:

mutating

And repeating:

repeating

And sorted (although this one could probably use some better food choices):

sorted

Zipping was an obvious win as well:

zip

And map vs flatMap:

flatmap

Unfortunately, a soccer ball is not a valid character identifier so I couldn’t bitcast between a European football and an America one. Inconsistent Emoji character sets made me sad. Swift needs a standards-based operator and identifier makeover:

unsafebitcast

By the time I started playing with fatalError, I realized I was spending way too much time on this:

fatalerror

Do you have any favorite Swift functionality that lends itself to emojification? I’ve showed you mine. Now, show me yours.

Update: Phil Aaronson suggests using emoji functions too.

Ideally, examples should be able to compile and run in a Swift playground but I’m open to concepts that can be better explained with Emoji even when implementation is tricky.

Holy War: Enum Hash Values and Option Sets

I recently engaged in a conversation on the Swift Users list about converting a JSON array of string values into an enumeration set. I somewhat tongue in cheek suggested that these values be converted into an string-based enumeration, and then their hashValues be used to set-up flags.

I was, of course, immediately (and rightfully) challenged on whether a solution should hinge on the hashValue implementation detail — it shouldn’t. But the more I thought about this, I wondered whether it might be reasonable to eliminate potential errors by using the hash values to guide the option set creation.

Here’s what I mean. Consider this enumeration:

private enum LaundryFlags: String { 
    case lowWater, lowHeat, gentleCycle, tumbleDry }

You can use the enumeration to populate an option set, knowing each hashValue will not overlap, allowing the compiler to choose the implementation details without ever touching them yourself:

public static let lowWater = LaundryOptions(rawValue: 
    1 << LaundryFlags.lowWater.hashValue)

This approach allows you to build option sets from strings but not worry what the raw values are. Whatever the compiler picks will be consistent:

// String based initialization
public init(strings: [String]) {
    let set: LaundryOptions = strings
        .flatMap({ LaundryFlags(rawValue: $0) }) // to enumeration
        .map({ 1 << $0.hashValue }) // to Int, to flag
        .flatMap({ LaundryOptions(rawValue: $0) }) // to option set
        .reduce([]) { $0.union($1) } // joined
    _rawValue = set.rawValue
}

There are limits. You cannot use enumerations to represent compound convenience members like the following examples:

public static let energyStar: LaundryOptions = [.lowWater, .lowHeat]
public static let gentleStar: LaundryOptions = energyStar.union(gentleCycle)

On the other hand, you can adopt CustomStringConvertible pretty easily even though raw-value enumerations do not report their members and cannot be initialized from hash values. As the following code shows, it’s not a huge burden to generate a lazy member dictionary. You can boiler plate the implementation and copy/paste your case list into this array:

static var memberDict: Dictionary<Int, String> = 
    [lowWater, lowHeat, gentleCycle, tumbleDry]
    .reduce([:]) {
        var dict = $0
        dict[$1.hashValue] = "\($1)" 
        return dict
}

Reduce the dictionary with bit math from the option set:

public var description: String {
    let members = LaundryFlags.memberDict.reduce([]) {
        return (rawValue & 1 << $1.key) != 0
            ? $0 + [$1.value] : $0
    }
    return members.joined(separator: ", ")
}

So here’s the holy war question: given how simple and reliable this approach is, do I back off of my “never use implementation details” guidance for raw value enumerations and their hash values?

Full gist is here.

Swift Holy War: Comments are not an Anti-pattern

Got into a debate yesterday about this write-up by developer Andrew Warner. His “Beware the Siren Song of Comments” suggests that developers delude themselves because comments detract from code quality:

Comments decay. They aren’t compiled, and they’ll never get executed at runtime. If they become out of date or incorrect, no test is going to fail and no user is going to complain. Programmers work around them out of fear that “somebody might need this comment or it might provide some value in the future”, pushing them along far after they’re useful (if you can even argue that they were useful in the first place).

His recommendation?

[Y]ou don’t have any excuse to write comments. Give these methods a try, and I promise you’ll have a cleaner codebase that’s easier to maintain.

I don’t claim that comments should counterbalance bad design decisions like poor naming or flawed algorithms. I do believe they play an important role in good coding practices — whether or not your code is meant strictly for internal use or to be consumed as APIs.

As I discussed on this blog a few weeks ago, there’s a big difference between the you writing code and “future you”, your team, and anyone else reading code. Here’s what I have to say about commenting in Swift Style:

Comment, comment, comment and while you’re at it, write tests. Tests can save you the whole “What I was doing here?” because you can just look at what is broken and what you expected to work.” It’s better to write less code and make up that time by explaining the code you did write better.

Sure, it helps to leave in a “TODO:” where it counts (“the performance is really bad here”) but while you’re at it, try to leave a few ideas about what exactly is going wrong, and what hypotheses you have rolling around your soon-to-be-extinct neurons. Past you understood things. Future you is clueless.

It always costs less to fix things in the past because you’ve invested in uploading the full design into your brain. Re-upping that design and getting back up to speed involves huge penalties.

Comments can explain the non-obvious, the tricky, or the counter-intuitive to a reader: This is intentional. This thing affects that thing. This data is not validated at this stage. Responsibility for this process now passes to this delegate. Comments enable you to establish what your assumptions are at which points in code and they allow you to comment on design qualities.

Comments create a record of intent. They may mention approaches that were tried and why they were abandoned. They may discuss how design decisions came to be — what paths were explored and why some of those paths weren’t chosen in the end.

Comments allow you to colocate thoughts with the code they refer to. Commit messages are helpful but I don’t think a commit message is  the proper place to document workarounds or unexpected behavior. Plus version control history may not travel with source code, if the code is reused in another project.

Comments provide a bread crumb trail of design decisions that aren’t kept in working memory and cannot be intuited just from reading code or scanning tests. Unexpected complexity is one of the things you’ll want to comment about. In fact, commenting on the unexpected is important because the alternative is essentially a bug.

Structured comments add another layer of utility, supporting API consumption. Markup allows these special comments to automatically convert into highly formatted local documentation supporting another set of readers beyond code review, debugging, maintenance, and enhancement.

Comments don’t just paper over bad design and coding. They document a process of making code right, supporting future reading and modification. Good comments reduce the mental effort needed by readers each time they review your source, enabling them to focus more on specific tasks like “how to I add this feature” rather than “what the hell was going on here”. While good code can at times be “self documenting”, that doesn’t mean it always is (or even usually is) self documenting.

As stepping stones to “past you”, good comments document what you were thinking and why you did things the way you did. Your past design decisions should never be a mystery or a burden placed before future readers of your code no matter how brilliant or insightful you expect them to be.

CGAffineTransform constructors and transformers

Core Graphics transforms provide control over coordinate systems, drawing contexts, and paths by enabling you to apply rotation, scaling, and translations. As I’ve been writing about Swift Style, I hope I’m now better able to articulate why I hate the way they’ve been automatically named into Swift.

The current Swift constructors and transformers are:

  • init(rotationAngle: CGFloat)
  • init(scaleX: CGFloat, y: CGFloat)
  • init(translationX: CGFloat, y: CGFloat)
  • rotated(by: CGFloat)
  • scaledBy(x: CGFloat, y: CGFloat)
  • translatedBy(x: CGFloat, y: CGFloat)

Here are my issues:

Confusing naming. “Scale” can be a noun or verb. You can only figure out which one was intended by looking at the translation API. If you have to look at another API to figure out some meaning, the API was written wrong.

In this example, if the two arguments were swapped around and balanced (xScale, yScale), the API would make a lot more sense. I’m not arguing for those terms. I just want to make the point that you should avoid using ambiguous words. This is a classic example of that error.

Missing Types. Why scale and translate by identical meaningless “x” and “y” values? Or rotate by “rotationAngle”? There are better, more exact terms of art and a couple of missing types to support those terms.

Although Core Graphics added CGVector, it is still missing two key types: CGAngle (stores radians or degrees)  and CGScale (stores sx, sy scaling factor pairs).

If I were in charge, you’d be able to initialize a CGAngle using radians, degrees, and π count (for example, 360 degrees is 2π and 45 degrees is 0.25 π). And you’d be able to pull out properties for each of those items as well from a unified structure. A CGScale would provide a natural way to store scaling factors.

Redundancy. If you can come up with a more redundant term than rotationAngle, I’d like to hear it.  rotationAngle uses two nearly identical words to do the work of one: “radians”. It presumes only one confusing initialization style while ignoring other common use cases like “degrees” and “multiples of pi”.

Incorrect Type Use. Although it’s convenient to break out factors into component elements, you’re really translating by a vector or scaling by an (sx, sy) pair. You should be allowed to use these types (for example, scale: CGScale) as well as the broken down member calls (for example, sx:sy:).  This is most notable in the use of CGVector. Although the CGVector type was introduced long after Affine Transforms, transforms were never updated to take advantage of  a semantically richer approach.

Mix and Match Prepositions. Core Graphics includes rotated(by:), scaledBy(), translatedBy(). So where does that “by” belong? In a coherent API, each “by” should either be in the parentheses or outside.

I vote “out”. Doing so enables you to create call families like these, where the specifics of the labels preserve share abstractions and the by isn’t glommed onto the first argument label, throwing off the API’s balance.

public func translatedBy(tx: CGFloat, ty: CGFloat) -> CGAffineTransform
public func translatedBy(vector: CGVector) -> CGAffineTransform

Speaking of unbalanced arguments, scaleX is way longer than y, as is translationX vs y, yet both arguments have equal weight and priority in the calls. Unbalanced labels offer another good indicator of badly designed APIs.