Swift Terms: arguments, parameters, and labels

Help me refine some terminology.

Start with this code snippet:

func foo(with a: Int) -> Int { return a }

You use arguments at call sites and parameters in declarations. This example function defines one parameter that accepts one argument from the call site, e.g. foo(with: 2). 

Apple’s Swift Programming Language book uses this approach:

Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.

The mighty Wikipedia writes:

The term parameter (sometimes called formal parameter) is often used to refer to the variable as found in the function definition, while argument (sometimes called actual parameter) refers to the actual input passed.

The Swift grammar lays out the external and local differentiation available to parameter declarations:

parameter → external-parameter-name local-parameter-name type-annotation default-argument-clause

Like Apple, I use label instead of name to refer to a parameter’s API-facing component outside of the grammar. The Swift Programming Languages refers to these as a custom argument label, naming it from the consumption POV. Apple writes:

By default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.

I generally call it a label or an external label instead. I often use parameter here (external parameter label, for example), especially when talking about the declaration. I don’t think there’s any real harm in doing so.

In this example, the parameter’s local or internal name is a. Some developers also call it the local or internal variable name. I find that word overloaded in meaning. Swift differentiates constants and variables and does not permit variables in function signatures.

I don’t have any problem calling it an internal argument name either because it’s the name given to the argument passed to the function or method. This seems slightly out of sync with SPL standards and practices. What do you think?

Holy War Part II: Son of Last Item in a Non-empty Array

Here are the two use cases motivating my Last Item in a Non-empty Array post. You can see the entire gist here.

The first method uses the guarantee of a non-empty array and notes it in an associated traditional comment. I have no problem with this. I should note that this second method is defined right after the method it builds on, and there’s little likelihood of confusion or review issues.

public func partitioned(where predicate: @escaping (_ element: Iterator.Element, _ mostRecent: Iterator.Element) -> Bool ) -> [[Iterator.Element]] {
    // `partitioned(at:)` guarantees a non-empty array
    // as its second closure argument
    return self.partitioned(at: {
        return predicate($0, $1.last!)
    })
}

The more serious problem is when you use the `partitioned(at:)` call outside the enclosing type. For example, you might want to partition an array at each point where the value changes:

testArray.partitioned(at: { $0 != $1.last! })

Looking at this one line of code, you have to make not just one but two mental leaps.

  • First there’s the correlation between the anonymous arguments and the call. Unlike partitioned(where:), which can be called for example with !=, this partitioned(at:) call takes two arguments, one of which is an element, and another an array of elements.
  • Second there’s the fact that there are no clues or information that the second anonymous argument is guaranteed to be non-empty, except if you note this in a comment or assertion or something like that.

If you use Xcode QuickHelp from this freestanding line of code, the non-empty guarantee is not visible:

The guarantee is only visible when used directly at the definition site:

Further, there’s a natural Swift coder tendency to question every exclamation point, namely: “Is this an intentional unwrap, with an expectation of failure should the unwrapping fail, or is it a naive use to shut up the compiler?”

Moving from forced unwrap to the lastOrDie workaround I mentioned in my original post makes user intent clear and explicit, and differentiates last from lastOrDie in Xcode’s pop-up completion list. It says: “This code should break on an empty array, which should never happen”. There’s a guarantee in place, implied by using lastOrDie.

You can mitigate forced unwraps with comments. (There’s an ongoing holy war about whether these kind of comments are appropriate or themselves bugs. Hi Soroush!)

// $1 is guaranteed as a non-empty array
testArray.partitioned(at: { $0 != $1.last! })

Or you can make the closure big and explicit. You might incorporate  an assert (will be removed from production code) or guard statement (won’t be), but this gets kind of ridiculous when you just want to force unwrap an item you know is going to be valid. Compare this mess to the original $0 != $1.last! solution:

testArray.partitioned(at: {

    (element: Int, currentPartition: [Int]) -> Bool in
    assert(!currentPartion.isEmpty, "Partition guaranteed to be non-empty")
    element != currentPartition.last!
})

Hopefully this provides the context missing from my original post. If you still have questions about why and how this is a problem, tweet, comment, or email. Thanks.

Holy War: Last Item in a Non-empty Array

Thoughts? Preferences? For the context behind this, see this post, and the screenshots in particular.

Option 1:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        assert(!self.isEmpty, "Array is guaranteed nonempty")
        let finalIndex = self.index(before: self.endIndex)
        return self[finalIndex]
    }
}

Option 2:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        guard let final = self.last
            else { fatalError("Failed to retrieve final array element") }
        return final
    }
}

Option 3:

extension Array {
    /// Return last element for array that is guaranteed 
    /// to have at least one element
    public var lastOrDie: Element {
        return self.last! // yes that's an exclamation point
    }
}

Option 4:

array.last!

Option 5:

// postfix operators cannot begin with either a 
// question mark or an exclamation mark.
postfix operator .!!!

extension Optional {
    /// "This unwrap is intentional" operator.
    /// G. Paltrow: "Conscious Unwrapping"
    /// Courtesy of: http://twitter.com/lapcatsoftware/status/856902513303449601
    public static postfix func .!!!(lhs: Optional) -> Wrapped {
        return lhs!
    }
}

Option 6:

How To: Finding your iTunes Connect Vendor ID number

Apple sent me an email:

Apple was recently notified that your bank account information has been manually corrected by the processing bank for iTunes payments to vendor [my personal vendor id number]. Unfortunately Apple cannot continue processing payments with the current banking details provided in iTunes Connect. To avoid unnecessary payment delays or returns, please log into iTunes Connect and provide the correct account information in Agreements, Tax, and Banking. For instructions on how to update banking, see ‘How do I add or edit a new bank account?’ in iTunes Connect Resources and Help. After the banking changes have been entered in our systems, payments will resume.

Oh shiny.

I pull out my latest statement and off I go to update my details. Here’s my problem. I don’t know which vendor account Apple is referring to. Like many developers, I use multiple iTC accounts. When I log into each one, I cannot find the vendor ID. Argh.

To save you lots of time, do this:

  • Log into any iTC account.
  • Manually navigate to https://reportingitc2.apple.com/reports.html
  • The vendor ID is listed next to your name. You should not have to re-authenticate when hopping from iTC to this page.

This helped me figure out which affected account was being referred to in the email and was able to update my info.

To update a direct deposit routing number, you need to hop into Agreements, Tax, and Banking. Click on the Bank Info > View button. You cannot edit the routing number in your existing Current Bank Account. Instead you need to Add Bank Account with the same details and the new routing number and then select that as your new account. Once you do it will take 24-48 hours for the change to go through and you will not be able to make further edits during that time.

The opinionated Tao of Optional Mappage

Given these two functions:

  • p(x) -> Void executes side effects in its body.
  • f(x) -> y produces a transformed value

Prefer:

  • if let x = x { p(x) } to x.map({ p(x) }) when executing a function for its side effects.
  • return x.map({ f(x) }) when returning a transformed value based on an optional.

You may think of map as inherently functional but x.map({ p(x) }) does not warn on unused result. In this case, the return type is Void. If  you assign the value, the compiler warns of the unexpected ()? return type.

I’ve often thought that forEach would be a better approach for procedural calls than map when working with optionals. This is based on the often disputed notion that optionals are like tiny collections with either zero or one members.

This is not how optionals are conceived, and the swift team has mentioned so on several occasions. Dmitri Gribenko wrote:

My argument is that map on collections and on optionals are two completely different things.  They unify on a level that does not exist in Swift (higher-kinded types).  We could name Optional.map() differently, and that would be a separate decision from renaming Collection.map(), but we used the name `map` primarily because of precedent, not because there is a HKT notion of these two operations
being the same…

I can’t say that it is not valid to think about an Optional as a tiny collection, but as implemented in Swift, .map() does objectively behave differently…Optional is a result of a computation that can fail.  .map() allows you to chain more things onto a computation if it succeeded, and do nothing if it failed already.

Until such things are resolved, you might consider replacing procedural calls on optionals with a custom forEach implementation:

extension Optional {
    public func forEach(perform action: (Wrapped) -> Void) {
        self.map(action)
    }
}

let x: String? = "Hello"
x.forEach { print($0) }

I think it better presents the notion that you’re not returning a value from mapping but executing a procedure for its side effects on any wrapped value within an optional.

What do you think?

Swift Documentation: Life Pro Tips

Swift Life Pro Tip: If you’re working with a Swiftized version of what was originally a Cocoa /Touch Foundation type, always check the header file just in case there’s more info that’s missing from the Swift version.

To take an example from a conversation today, consider the following code. What happens if you pass nil rather than an actual locale?

let string = "istanbul"
print(string.uppercased()) // ISTANBUL

import Foundation
let locale = Locale(identifier: "tr")
print(string.uppercased(with: locale)) 
// İSTANBUL, with the dot over the I

print(string.uppercased(with: nil))  // ??

Swift

Cocoa/Touch Foundation

Looking up Headers

The header files use traditional comments that I assume aren’t picked up by automatic document generation:

  1. Look up declaration for the NS version of a Swift Foundation class, such as NSString vs String.
  2. Click Objective-C and away from Swift.
  3. De-swiftize the `uppercase(with:)` declaration. In this case, the ObjC declaration is, `- (NSString *)uppercaseStringWithLocale:(NSLocale *)locale;`
  4. Find the header file (I have System/Library/Framework on perma-symbolic link from my home folder) and look there for NSString.h.
  5. Look at the original declaration in the header file:
/* The following methods perform localized case mappings based on the locale specified. Passing nil indicates the canonical mapping. For the user preference locale setting, specify +[NSLocale currentLocale].
*/

Hope this helps someone.

Tangentially, Zev Eisenberg reminds me to link to the Swift String Manifesto, which addresses a bit of this issue.

Got other Swift Life Pro Tips? Drop a comment, a tweet, or an email. Thanks!

Stupid Swift Tricks: Sleepsort

Was chatting today about the freestanding old style partition function and the new one that’s part of SE-0120. One thing led to another and I was writing sleepsort in a playground.

Several interesting things.

  • To Linuxize, so I could run this in the IBM sandbox, I had to import Dispatch, use CLOCKS_PER_SEC, and use rand() (and no, I didn’t even bother seeding it, I just wanted the code to run).
  • Bad things™ happened without the access queue, as the quality of service was not quite as good as I initially thought.
  • I had to tweak the delay time between the Linux and playground implementations a bit so closures didn’t fire unexpectedly and wouldn’t run over each other. Maybe I should have gone with a different policy than default for my primary dispatch method?

As always, if you have improvements or suggestions, fire ’em away.

Bridging Swift Generics with Darwin Calls

Seth Willits was working on an interpolation protocol that would allow conforming constructs to interpolate from one value to another, regardless of their underlying types. It needed to work for CGFloat as well as Double, and be decomposable and useful for CGPoint and CGRect as well as any custom Swift Polygon struct.

This created interesting challenges, as some of the most fundamental animation curves use exponentiation, which is not built into the Swift standard library. So I turned to pow, which is only defined for float and double:

public func powf(_: Float, _: Float) -> Float
public func pow(_: Double, _: Double) -> Double

In the past, I’ve created horrible bridging solution that permits migration from most floating point values to double. It’s not beautiful but I decided to pull it out from my toolkit and introduce it to this problem.

What I did was to build an extension on BinaryFloatingPoint that returned an interpolated value along a styled curve. My hack let me create a single interpolate method that applied across floating-point. I bridged to Double to use the Darwin pow function:

There’s an interesting CGFloat bug in play here, where the value history does not display as a graph but the numbers are right and work properly during animation.

Here’s the code. Shout out your improvements and alternatives.

Style this: Image Name

The Code

This episode of “Style this” stars code from Brandon Trussell, who asked to “make this Swiftier”:

// Get the image name
var imageName: String? = nil
if let collection = songs {
    for song in collection {
        if (song.cover_url != "") {
            imageName = song.cover_url
            break;
        }
    }
}

The Issues

So what’s wrong with this code? Here’s a quick overview.

Naming. There’s a mismatch here between imageName and cover_url. Is it a name? A URL? What? Turns out that this is a string, such as “ExperienceHendrix.jpg”. Both the cover_url property and the local imageName variable should reflect this better. And they do so without unsightly snake case naming. Fix: Rejigger the names to reflect that these are local file names and use standard Swift camelCase naming.

Parenthesized conditions and semicolons. The parentheses in the empty string check and the semicolon after the break are holdovers from Objective-C. Train yourself away from these reflexive habits. They’ll compile in Swift but they’re unnecessary. Fix: Ditch the parens and semicolon.

Comparing against an empty string. It’s bad form to test against an empty string or check if a collection’s count is zero. Prefer using the isEmpty property, which offers better semantics and performance. Fix: Refactor the empty string check.

Using an empty string instead of an optional. There’s a design flaw here in that this model should really use an optional String instead of an empty string to begin with (thanks Dave DeLong), but that’s another fish to fry that this redesign won’t address. In Swift, an optional represents the absence of a value in a way that an empty string does not convey.

Using the wrong type. The right type for a local file asset should be a file URL, not a string. Again, this redesign won’t address that.

Complex iteration: When you’re looking for the first member of a collection that satisfies a predicate, go functional. The Standard Library offers many ways to convert iteration that uses extra state (in this case the imageName variable) into a cleaner function call. Fix: use first(where:), which you get for free as part of the standard library.

Unnecessary conditional binding: If you’re going to use an optional value exactly once to extract some value and you can transform that binding into a function call, consider optional chaining instead. Fix: use songs? with a function.

The Refactor

Here’s what a refactored and Swiftier version of Brandon’s code might look like. This rewrite returns an optional string. That string contains the first non-empty coverImageFileName property within the songs collection. I think it’s a simpler approach with better naming and tighter code.

// Extract the file name for the first cover image
// found within the optional `songs` collection
let firstCoverImageFileName: String? = songs?
    .first(where: { !$0.coverImageFileName.isEmpty })?
    .coverImageFileName

Note that both calls in the functional chain require question marks. The first one, after songs, reflects that songs is an optional collection. The second, after the first(where:) call supports potentially nil searches (for example, where a collection has no covers).

This code won’t compile without that second question mark. Swift will, however, warn you at compile time that you’re attempting to make a call on an optional type if you omit it.

Soroush Khanlou, Dave DeLong, and Tim Vermeulen put their heads together for a slightly different approach:

let firstCoverImageFileName2: String? = songs?
    .lazy.flatMap({ $0.coverImageFileName })
    .first(where: { !$0.isEmpty })

Using a lazy flatMap may be a bit harder to wrap your head around, but it’s beautiful in that it pulls each image name, and then returns the first non-empty one, ensuring that you don’t create any intermediate storage.

Tim further adds:

extension Sequence {
    func firstResult<T>(_ transform: (Iterator.Element) -> T?) -> T? {
        for element in self {
            if let result = transform(element) {
                return result
            }
        }

        return nil
    }
}
let firstCoverImageFileName: String? = songs?
    .firstResult { 
        $0.coverImageFileName.isEmpty ? nil : $0.coverImageFileName }

and, as an alternative:

extension Optional {
    init(_ value: Wrapped, where predicate: (Wrapped) -> Bool) {
        self = predicate(value) ? value : nil
    }
}

songs?.firstResult { 
    Optional($0.coverImageFileName, where: { !$0.isEmpty }) 
}

Also, I threw together this, which I’m not sure if I hate or not:

extension Sequence {
    func first<T>(
        apply transform: @escaping (Iterator.Element) -> T?, 
        where predicate: @escaping (T) -> Bool) -> T? {
        return self.lazy
            .flatMap({ transform($0) })
            .first(where: predicate)
     }
}

songs?.first(apply: { song in song.coverImageFileName }, 
    where: { name in !name.isEmpty } )

Swift Style

Agree with these refactoring recommendations? Disagree? Would you redesign this differently? Drop a comment or send a tweet. Swift Style is now available to order as a paper book, an ebook, and a paper/ebook bundle.

Tip of the hat to Mike Ash who was also offering feedback. Thanks to Soroush Khanlou, Dave DeLong, Tim Vermeulen, Zev Eisenberg