Archive for the ‘Swift’ Category

Matching Regular Expressions

Last week, I wrote about Olivier Halligon’s elegant Set matching solution. Several people asked if this could be extended to pattern matching for other types, which it can. Today, I put together a little proof of concept for performing regular expression matching with strings.

I started off with the same struct plus stand-alone global pseudo-constructor approach I had used with sets. Doing so, let me have a RegexPatternMatcher type and implement a matching function to hide a constructor. After a bit of playing around,  I dropped the global function to use a normal initializer: RegexPatternMatcher("pattern") vs matching("pattern"). The call sites were longer but less garbage floating around.

Renaming the type to Regex provided a more succinct approach : Regex("pattern"). I don’t normally like using overly short type names to balance call sites but I felt that Regex said about all that needed to be spoken here:

I’m not a huge fan of NSRegularExpression. I can’t wait for a native Swift solution. The class is expensive and it relies on what feels like archaic string models that use NSRange. Olivier suggested I balance the expense with NSCache so I created a variation where converted my struct to a class, and used NSString patterns as the cache keys.

This allowed me to build each NSRegularExpression instance once and decouple the matching options from the pattern. I made the class match function ignore defaulted option arguments. Instead, I allow the cache to carry forward any matching policies that previously existed or overwrite those policies if you specify them explicitly.

There’s something wrong with my code because I could not get a cached regex to change its matching behavior even after I updated options. Look at lines 103 through 107 in this version. If you figure out what’s wrong, let me know. It returns true for all six tests, instead of four true then two false.

Anyway, it was an interesting exercise and a good way to start getting back to work as I recuperate.

A Beautifully Elegant way to Set-Match

Challenge: By default, Swift’s switch statement uses equality matching when testing Set instances (for example). So how can you switch that up to use containment instead of equality? For example, say you want to test a set of insets presented as Set<Inset>? Here’s the standard Swift solution for containment:

switch insets {
case let sides where sides.isSuperset(of: [.top, .bottom]) : ...
case let sides where sides.isSuperset(of: .top) : ...
case let sides where sides.isSuperset(of: .bottom) : ...
}

It’s not awful, but couldn’t there be a more beautiful way to allow pattern matching against a set using a more Swifty statement that didn’t abuse its where clause?

Solution: Olivier Halligon came up with the following approach. He built a custom Set containment struct whose pattern matching operator (~=) is customized to apply superset detection:

public struct SetContainmentMatcher<T: Hashable> {
    public let set: Set<T>
    
    public static func ~=(
        lhs: SetContainmentMatcher<T>, 
        rhs: Set<T>) -> Bool {
        return rhs.isSuperset(of: lhs.set)
    }
}

public func containing<T>(_ set: Set<T>) -> SetContainmentMatcher<T> {
    return SetContainmentMatcher(set: set)
}

To use, build your switch using the now-global containing function. The function enables you to test your set against other sets using standard switch pattern matching.

public enum Inset { case top, bottom, left, right }

let sides: Set<Inset> = [.top, .right]
switch sides {
case containing([.top, .bottom]):
    print("contains: top, bottom")
case containing([.top]):
    print("contains: top") // matches here
case containing([.bottom]):
    print("contains: bottom")
default:
    print("default case")
}

Nice, isn’t it? Make sure to test for the largest sets first. If you invert the logic here, testing [.top] before [.top, .bottom], you may end up with unexpected behavior.

More good reading here on Olivier’s blog.

Swift 5 begins: new evolution rules will require implementations for language change review

Ted Kremenek writes about Swift 5 on the Swift Evolution list. Among other changes, SE proposals will now require implementations before Core Team review. Swift 5 will focus on ABI stability and concurrency.

The proposal phase for Swift 4 is now officially over, and the release is now in endgame engineering convergence for an expected release later this year. Swift 4 has turned out to be one of the highest quality, well-rounded releases of Swift, and I am grateful to everyone in the community who made this release come together!

Now it is time to turn our attention to Swift 5. I have just posted updates to the README.md file on the swift-evolution repository, which outlines the core themes and focus areas for Swift 5:  https://github.com/apple/swift-evolution and a more persistent URL (invariant to future README.md changes): https://github.com/apple/swift-evolution/blob/9cc90f33b6659adeaf92355c359e34e6fed73254/README.md

I am not going to repeat all of that information here, but I wanted to highlight a few important things.

ABI Stability

First, ABI stability is the center focus of Swift 5 — and we will pivot much of our prioritization of efforts for Swift 5 around it. With Swift 4, ABI stability was a strong goal. In Swift 5, it is a requirement of the release. Whatever ABI we have at the end of Swift 5 is the ABI that we will have. ABI stability is an important inflection point for the maturity of the language, and it cannot be delayed any longer.

Please note that there is a difference between ABI stability and module stability. If you are not aware of the difference — which is rather important — please read the first few paragraphs of the ABI stability manifesto: https://github.com/apple/swift/blob/master/docs/ABIStabilityManifesto.md

Module stability is a stretch goal for Swift 5, but even without module stability we can still achieve the primary value of ABI stability.

Other focus areas (including laying the groundwork for concurrency)

There are several other areas mentioned for Swift 5 which I won’t repeat here, but there is a general theme of refining and broadening out the core ergonomics of the language and standard library.

One of those that I wanted to highlight is laying the groundwork for concurrency. It is a non-goal of Swift 5 to roll out a full new concurrency model. That is simply too large an effort to do alongside ABI stability. However, it is important that we start making progress on discussing the directions for concurrency and laying some of the groundwork. This may take the form of specific enhancements to the language that get implemented, depending on where the discussions for concurrency lead and how they align with the priorities for delivering ABI stability in Swift 5.

Changes to the language evolution process

Last, I want to highlight important changes to the evolution process for-swift-5:

With Swift 4, the release period was divided up into “stage 1” and “stage 2” for setting guidelines for the kind of evolution proposals that were in scope for the release. This was needed to establish focus — especially after the churn we saw during Swift 3 — on some core themes that were aligned with converging the language towards source & ABI stability. One downside is that “stage 2” opened up discussion for potentially disruptive changes fairly late in the release. Further, some proposals — such as SE-0155 — came in so late that there was little runway to actually implement them for Swift 4, let alone evaluate their impact in practice on real projects. Related, there has been some desire for a while to be able to better evaluate the impact of proposals on real code before they are locked into the release, and the best way to do that is to actually have an implementation that vets out the design in a proposal.

With Swift 5, the focus on ABI stability will predominate priorities for both design and implementation work, but the Core Team did not want that focus to stifle all discussion on potential enhancements to the language that were not fundamentally tied to that primary goal. After reflecting on the evolution process during both the Swift 3 and Swift 4 releases, the Core Team felt that we could strike a balance with not diluting attention from ABI stability while still enabling a broader range of proposals compared to Swift 4 by requiring that all proposals have an implementation before they are officially reviewed by the Core Team. An implementation can come long after an idea has been pitched and after a proposal has been written. However, before a pull request for an evolution proposal will be accepted — and thus an official review scheduled — an implementation must be in hand for a proposal as part of the review. The existence of an implementation does not guarantee that the proposal will be accepted, but it is instrumental in evaluating the quality and impact of the proposal.

There are two key benefits of requiring an implementation:

  1. It encourages a design in a proposal to be more thoroughly fleshed out before the proposal is formally reviewed. The hope is that this will make the review process both more efficient as well as more effective.
  2. An implementation allows the proposal to be evaluated on real world code and not just the examples that are in the proposal.

The Core Team is also sensitive to proposal authors investing time in providing an implementation for a proposal that is not likely to get traction. The Core Team will be regularly reviewing potential proposals, and provide feedback either during the pitch stage or when a proposal is submitted via a pull request on whether or not the proposed change looks within the charter of the release or meets the criteria for a valuable change to the language.

Requiring an implementation naturally raises the bar for proposals. While this is by design, it can possibly have the negative aspect of making some feel the bar is too high for them to participate in the Swift evolution process. As an open source project, both the design and implementation of the language is a highly social endeavor, and we encourage the community to collaborate on both the design and implementation of proposals. Specifically, it is not a requirement that the original author(s) of a proposal be the one who provides an implementation — all that matters is that there is an implementation when a proposal gets reviewed.

Lastly, an important aspect is that unlike Swift 4, the broadening of scope for proposals considered for Swift 5 begins… now! Proposals that fit within the general focus of the release are welcome until March 1, 2018. Proposals will still be considered after that, but the bar will be increasingly high to accept changes for Swift 5.

  • Ted

Dear Erica: How do I simplify `Swift.print`?

Dear Erica:

In other languages (Python mostly comes to mind, but I think ml and probably Haskell as well) you can essentially create a new name for a function by assigning it to a variable and use that instead.  All type information and usage follows with it.

I use it a lot in Python to have a local variable that’s  already bound to some otherwise nested module call. It saves some lookup time and textual typing. (Gotta be explicit since syntactic typing is relevant in Swift.) In trying to work around the problem of “print” calling  NSDocument.print, I tried declaring a val at the top level:

let Print = Swift.print // for print to console

The compiler seemed happy with the definition but when I tried to use it as in:

Print(“in makeWindowControllers”)

I got:

Hitting Fix did nothing but I wasn’t really expecting much (this is Xcode 9.0 beta). I assumed it wasn’t  telling me to literally put <#String#> in as a second parameter but that the type inference was inferring a type of String for  parameter #2  It didn’t really make any sense (why would a second parameter be required for a variadic argument?) If two, why not 3…?

So I tried the following but to no avail:

Print(“in makeWindowControllers","two”)

One can obviously write a full function which works fine:

func Print(_ items:Any...) -> () {
    print(items) 
} 

Print("in makeWindowControllers")

It’s pretty simple but seems unnecessarily heavyweight. I can’t seem to find any way to do a variadic closure. Is this possibly a bug or am I missing something obvious? Is there any reason the simple value declaration shouldn’t work? I know I’ve seen complaints about the lack of an Apply function in Swift. Not sure if this is related. My functional mojo is somewhat lacking…

This is a terrific question, and I’m going to answer it in several parts.

First, the full signature of Swift’s version of print is

public func print<Target>(_ items: Any...,
    separator: String = default, 
    terminator: String = default, 
    to output: inout Target) 
    where Target : TextOutputStream

See all those default items?  They don’t travel nicely to closures.  Second, take careful note of the variadic items, because you can’t pass them along by redirecting them to another function. Your “full function” actually prints an array of the items you pass:

Print("Hello world") // prints ["Hello World"]

The only way around this for 10.12 and earlier is to re-implement print (or a reasonable facsimile). Having tried that this morning, I warn you, it is a doozy. Seriously. You wouldn’t believe how many functions and files go into this one little call.

Fortunately, this name-overlap problem (NSView.print vs Swift.print, etc) is fixed in High Sierra. The 10.13 release notes write:

print() methods in Swift: NSWindow, NSView, NSDocument’s print() instance methods have been renamed to printWindow(), printView(), and printDocument() respectively in Swift 4. This fixes the unexpected experience where adding debug logging to a subclass of one of these instances shows a print panel instead.

You can help the variadics don’t propagate cause (“El viva variadics!“) by filing a radar. Go ahead and dupe, mentioning rdar://problem/12134482.

For the moment, here’s a less capable workaround you can use. It does pretty much what you want with slightly reduced capabilities (and complexity) compared to the built-in Swift.print solution.

public func sprint(
    _ items: Any...,
    separator: String = " ",
    terminator: String = "\n")
{
    var prefix = ""
    for item in items {
        Swift.print(prefix, terminator: "")
        Swift.print(item, terminator: "")
        prefix = separator
    }
    Swift.print(terminator)
}

It’s kind of a production-unfriendly workaround for just avoiding Swift.print, but I hope this helps anyway.

Thanks Dave, Tim, Stephen, Caleb

Beta 3 Playground Workarounds

Adding Resources and Sources folders to Playgrounds

Until they’re fixed, you may have to add them by hand.

  1. Right-click/control-click.
  2. Show package contents
  3. You can add new Resources and Sources files at the top level
  4. Alternatively, navigate down to individual pages (which are finally in Beta 3!) by showing their package contents and add them there

Fortunately under Beta 3 you don’t have to manually add pages, as the new page functionality is finally back.

Creating New Playgrounds

They’re no longer listed in the File > New dialog. Instead choose File > New > Playground (Command-Shift-Option-N) or open “Welcome to Xcode” (Command-Shift-1) and click “Get started with a playground”.

Most of the obvious alternatives (like Command-Control-N, which creates new workspaces) are already taken, but if you don’t mind using the menu for that, I think it’s a nicer key binding for “New Playground”. If you want to mess with this open prefs (Command-comma), type playgrounds into the search field, and edit the key binding for “New > Playground”

Don’t forget that new playground page is “Command-Option-N”.

Result types

How do I use result types? When using a Result enum for callbacks, how to access the Error?

The most common Result enumeration looks like this:

enum Result<Value> { 
    case success(Value), failure(Error) }

A Result is used almost exclusively in completion handlers. In synchronous code, it’s more common to use throwing functions rather than Result types:

do {
    let value = try throwingFunction(...)
} catch {
    ... handle error ...
}

A Result type replaces the (value: Value?, error: Error?) -> Void handler signature used by many Cocoa APIs with this single Swift enumeration. Handling this type requires a slightly different approach than you’d use with thrown error handling.

As a rule, if an error is generated on your behalf, pay attention to it and don’t discard it out of hand. Errors help identify underlying issues that you may be able to resolve. They also provide important information for the developer and end-user of why an operation has failed.

The switch statement provides the simplest approach to handle both result conditions with equal priority:

switch result {
case .failure(let error): 
    // handle error here
case .success(let value): 
    // handle success here
}

If the error handling code is significantly less detailed than the success code, you might choose to perform early exit instead of using switch. This approach allows you to handle any errors and then move on to processing the returned value at the top scope.

Use an if statement (not a guard statement) to bind error instances. Its primary clause should handle the bound error  and then leave scope.  If the result is success, the if-test will fail. Follow the error check with a guard statement to bind the success value.

if case .failure(let error) = result {
    // handle error
    return
}
guard case .success(let value) = result 
    else { fatalError("Success value could not be bound") } // this should never happen

// use value

This second approach allows you to promote the typically detailed steps involved in processing a value after extracting it from the Result enumeration. The guard‘s else clause is a little ugly but necessary. Swift doesn’t offer a “forced enumeration unwrap” similar to Optional‘s !.

Breaking the handling down into an if/guard pair is not as elegant as the unified switch statement, but it provides a practical way to promote the importance of the returned value.

Update: If the !! operator is ever adopted, you could extend Result to return a computed var value: Value? member, and then use !! instead of the guard/fatalError combo in the above example to create a streamlined early return / value handling approach:

if case .failure(let error) = result { ... }
let value = result.value !! "Success value could not be bound"

It’s a lot cleaner. See this PR for more details. (Thanks Dave)

Pronouncing “Tuple”

A tuple is a finite ordered list of elements. It is presented as a parentheses-braced, comma-delimited list. In Swift, you can use them as stand-alone heterogenous lists of values or pass them as arguments to functions and closures.

A tuple is pronounced “tupple” (TUH-ple), not “two-pull”. It’s a shortcut pulled from “double, triple, quintuple, sextuple, octuple”, etc. Yes, please note that “quadruple” doesn’t fit with the others and is not used as a basis for speaking the word. Rules about long and short “u”s that apply to other English words are also not relevant to this case.

In Swift, a tuple is analogous to an anonymous struct. Its members are indexed numerically (.0, .1.2, etc). You can also use labels to access members by name:

let point = (x: 5.0, y: 2.3)
print(point.1) // 2.3
print(point.y) // 2.3

Swift 3.0 and later no longer supports splatting, so you cannot decouple a tuple from a function call. You can read more about this in SE-0029, which disallowed the ability. Before the change, you could call a function either with its direct arguments or by passing a tuple:

func foo(a : Int, b : Int) {}
foo(a: 42, b : 17) // still allowed
let x = (a: 1, b: 2)
foo(x) // no longer allowed in Swift 3+

The continued work on SE-0110 is still resolving on how tuples and closures interact.

The word “arity” describes the number of members in a tuple. (It also describes the number of arguments or operands accepted by a function, method, or closure.) The examples above use an arity of 2. You can call this a “2-arity tuple” or the shortcut “2-ary tuple”. Some shorten that further to a “2-tuple”.  All are acceptable.

Some fun facts to finish with:

  • A figurative tuple with an arbitrary arity is an “n-arity” or “n-ary” or “n-tuple”.
  • A tuple with a variable number of arguments is variadic.

Working with optional errors in completion handlers

Foundation likes to pass optional errors (versus, say, a unified Result type) to completion handlers. A typical closure uses a (Value?, Error?) -> Void signature,where Value is some sort of data result that varies by operation.

A colleague was struggling to use conditional binding along with casting in his handler. Leaving aside for the moment any rational need to cast to NSError, this is an interesting demonstration of how you perform these two operations synchronously in code.

A cast from Error to NSError is guaranteed to succeed, so you can use the as operator. However, you must phrase the cast just right. Otherwise the Swift compiler emits warnings, as you see in the following screenshot. Here is an example of how you don’t get this job done properly:

As my friend complained in frustration: “But it tells me “did I mean as” and when I switch `as?` to `as` then it complains that error is Error? and isn’t convertible to NSError.

This attempt followed the normal pattern of conditional casting. Swift automatically lifts double optionals into a single optional result when used this way, but the cast from Error to NSError will always succeed, so you can’t use as? here.

To resolve, use a non-conditional cast to NSError? and then perform conditional binding to unwrap the value:

enum Bad: Error { case luck }

let error: Bad? = Bad.luck

if let error = (error as NSError?) {
    print("Worked")
}

The parens around the non-conditional cast make all the difference. Swift removes its warnings and makes everything work as expected.

More on SE-0110: Important fallout, please read (Updated)


Update: Statement from Austin

…I’d like to appreciate my heartfelt thanks to everyone who reached out to me one way or another. It’s clear to me that the Swift, Apple platform developers, and swift-evolution communities are amazing, and that the people in them are kind, wonderful, generous, passionate, and caring. The Core Team in particular has done an incredible job shepherding the community, befriending people on and off the lists, and leading an open-source project of great technical and social complexity.

After thinking about things, I plan to continue participating in swift-evolution and looking for new ways in which I can serve the Swift and Apple developer communities. I hope to listen more, speak less, be more sensitive to other peoples’ feelings, and offer fair, well-considered feedback.


Often the Swift core team will ask for community help to develop and sponsor a proposal. I’ve worked on several of these. These proposals are generally aimed towards simplifying the compiler, enhancing the language, or addressing technical issues that place stumbling blocks in the effective delivery of compilation.

The reconsideration of SE-0110 should not reflect in any negative way on Austin Zheng. He worked hard on a proposal whose intent was to serve the large Swift developer community. I congratulate Austin for shepherding through this proposal, which can be a long, frustrating process.

The usability regression was unexpected. I applaud the core team for its flexibility in responding to the community’s real concerns when its implementation showed issues.

Today, Austin tweeted:

If my posting of the SE-0110 notice last night contributed to a negative atmosphere, I apologize. I have written to Austin and I hope he will reconsider his decision and rejoin Swift Evolution.

On the SE-0110 Regression (full text)

Doug Gregor writes:

Hello Swift community,

Swift 3’s SE-0110 eliminated the equivalence between function types that accept a single type and function types that take multiple arguments. However, for various implementation reasons, the implementation of SE-0110 (as well as the elimination of tuple “splat” behavior in SE-0029) was not fully completed.

 

Swift 4 implemented more of SE-0110, which caused a fairly serious usability regression, particularly with closures. Here are a few simple examples involving closures that worked in Swift 3 but do not work in Swift 4:
// #1: Works in Swift 3, error in Swift 4
myDictionary.forEach {
  print(“\($0) -> \($1)”)
}
 
// #2: Works in Swift 3, error in Swift 4
myDictionary.forEach { key, value in
  print(“\(key) -> \(value)”)
}
 
// #3: Works in Swift 3, error in Swift 4
myDictionary.forEach { (key, value) in
  print(“\(key) -> \(value)”)
}
Similar issues occur with passing multi-argument functions where a tuple argument is expected:
// #4: Works in Swift 3, error in Swift 4
_ = zip(array1, array2).map(+)
In all of these cases, it is possible to write a closure that achieves the desired effect, but the result is more verbose and less intuitive:
// Works in both Swift 3 and Swift 4
myDictionary.forEach { element in
  let (key, value) = element
  print(“\(key) -> \(value)”)
}

 

The Swift core team feels that these usability regressions are unacceptable for Swift 4. There are a number of promising solutions that would provide a better model for closures and address the usability regression, but fully designing and implementing those are out of scope for Swift 4.  Therefore, we will “back out” the SE-0110 change regarding function arguments from Swift 4.

 

Specifically, when passing an argument value of function type (including closures) to a parameter of function type, a multi-parameter argument function can be passed to a parameter whose function type accepts a single tuple (whose tuple elements match the parameter types of the argument function). Practically speaking, all of the examples #1-#4 will be accepted in both Swift 3 and Swift 4.

 

We will revisit the design in this area post-Swift 4.

 

– Doug