Archive for March, 2016

Swift First Labels: Bring ’em back

Today Joe Groff asked whether the first parameter in a function declaration should follow the same rules as the remaining parameters.

Our accepted naming guidelines have embraced first argument labels for functions and methods. This weakens our justification for making the first parameter declaration in a `func` declaration behave differently from the others, implicitly being unlabeled. It seems pretty clear to me we should make all of the parameter declarations behave uniformly:

func foo(x: Int, y: Int) // Should declare foo(x:y:)

instead of foo(_:y:)

func foo(_ x: Int, y: Int) // Explicitly declares foo(_:y:)

This would also make `init` and `func` parameters behave consistently, which is nice. There may still be hope for our keyword argument rules to one day be shorter than the Smalltalk spec…

I endorse this. Swift’s guiding principles are clarity, concision, and consistency. The history of leading-labels from Swift 1 to Swift 2 and now to Swift 3 showcases a place where language design swerved to better serve Cocoa/Objective-C standards and now returns to  the emerging needs of a new and distinct language.

Swift supports Objective-C interoperation but the language is not Objective-C. There’s still a great need to support, bridge to, and interact with legacy code but that support should not drive Swift’s  design.

A natural turbulence exists between Swift’s design principles and the existing body and APIs of Cocoa code. From error handling to type safety, method signatures to core types, Swift needs to focus more on being Swift and less on feeling familiar to transitioning developers, especially as more users hop onboard from non-Apple platforms and languages.

Generic Typealiases are a thing

on Mon Mar 07 2016, Chris Lattner <swift-dev-AT-swift.org> wrote:

Hi All,

I just landed an implementation of generic typealiases, e.g. things like:

typealias StringDictionary<T> = Dictionary<String, T>
typealias IntFunction<T> = (T) -> Int
typealias MatchingTriple<T> = (T, T, T)
typealias BackwardTriple<T1,T2,T3> = (T3, T2, T1)

etc now work.

I have tested various scenarios with them, but I wouldn’t be surprised if there are corner cases that aren’t working yet.  Please try kicking them around and let me know if you run into any problems, thanks!

“I am become generic, the typealias of worlds” — C. Lattner

Strap your Swift 3 seat belts. It’s going to be a bumpy ride.

From Max Moiseev on swift-dev

Re: merging Swift 3 branches into master

As you all are probably aware, we’ve done a lot of work on API Naming Guidelines recently. Standard Library has changed significantly to adopt new names. swiftpm, swift-corelibs-foundation, swift-corelibs-xctest, and swift-lldb have also been ported to Swift 3.

The work has been tracked in separate branches so far, and now it’s time to merge them all into master. We are planning to perform this merge in coming days.

Please raise your concerns, should you have any.

max

Swift Evolution: a handful of things

I was going through my notes this morning and found an informal (and very incomplete) list of items that I’d really love to see happen in Swift. Several of these came up in discussions but for whatever reason never progressed to a formal proposal or from a proposal to a review or were discarded as something the Swift team would prefer not to pursue.

I thought I’d share a handful of them.

Better Compiler Directives

Discussed at a variety of times under several topics, these directives include the canonical Evan Maloney suite  (Apple/Non-Apple Platform, common UIKit platform, debug/release, simulator/physical, test-supporting), Darwin-support, and the classic William Dillon (big-or-little endian/32-or-64-bit/signed-or-unsigned char) collection.

These directives involve minor changes, are easy to implement, and can be extended over time as needed. It would probably be best to get a sense of which ones the dev community *really* wants and needs and push on those to avoid clutter, but I’d hate to see these languish.

Eliminating the Weak-Strong Self Dance

Discussed quite a bit, there’s a bug that (normally) lets you do

guard self = self else {...}

but nothing that adopts this into the language as-yet. It would be such a relief to be able to convert a weak self reference to a strong one to simplify completion blocks.

Better Option Sets

I know Swift is unlikely to adopt a fourth core type, but surely it would be better and nicer to be able to declare

public optionset Features {case alarmSystem, cdStereo, chromeWheels, pinStripes, leatherInterior, undercoating, windowTint}
than
public struct Features : OptionSetType {
    public let rawValue : Int
    public init(rawValue: Int) {self.rawValue = rawValue} // workaround, :(, silly Apple
    
    public static let AlarmSystem = Features(rawValue: 1 << 1)
    public static let CDStereo = Features(rawValue: 1 <<  2)
    public static let ChromeWheels = Features(rawValue: 1 <<  3)
    public static let PinStripes = Features(rawValue: 1 <<  4)
    public static let LeatherInterior = Features(rawValue: 1 <<  5)
    public static let Undercoating = Features(rawValue: 1 <<  6)
    public static let WindowTint = Features(rawValue: 1 <<  7)
}

The current system lets you combine options together, for example:

public struct LaundryOptions: OptionSetType {
    public static let EnergyStar: LaundryOptions = [.LowWater, .LowHeat]
    public static let LowWater = 1, LowHeat = 2
}

but I can’t imagine that it would really be that hard to expand an option set type to do the same:

public optionset LaundryOptions {
    case lowWater, lowHeat
    compound energyStar = [.LowWater, .LowHeat]
}

This is most likely to be implemented through some kind of Macro system, as it currently is in Rust. (Thanks, Lily)

Struct Inheritance

This is one that gets brought up occasionally, discussed, and then disappears into the wind. There’s probably no right way to do it and I understand the complexity, especially when you’re talking about overriding methods, and keeping to a value type system.

Inheritance would enable you to have direct access to members while extending with new members, without having to wrap everything in a new type and then provide custom ways to forward embedded types to be externally visible.

I’d also settle for less “inherit-y” composition, so long as the results are more or less the same.

Enum Case Collections

“It is a truth universally acknowledged, that a programmer in possession of an enum with many cases, must eventually be in want of dynamic enumeration over them.” This has a proposal but is otherwise just sitting there.

Other Stuff

This just scratches my list. Other things like decimal types, re-imagining ranges and intervals,  extended guard constructs, and cascading can probably wait for the deluge to pass.

What’s on your list of stuff you’d really like to see make the Swift cut?

Swift Queue fun

There are many ways to write Queues in Swift, but wrapping an Array is about as easy a solution as you can get. You get all the push/pop behavior for free. (Yes, there are better solutions for complexity, but I really want to show off ArrayLiteralConvertible in this write-up.)

Wrapping an Array

Start with a basic struct to envelope your queue:

public struct Queue<T> {
    public private(set) var elements: Array<T> = []
}

Notice the private(set) modifier for elements. This restricts the read-write scope of the property. Your elements are visible but cannot be  set outside the file that declares them.  This “private” behavior can surprise you in playgrounds, where your timeline acts as a single file.  Consuming the queue in the same timeline means private elements can be overridden. This is an unusual use-case.

var q = Queue(elements: [1, 2, 3]) // 1, 2, 3
q.elements = [4, 5]
q.elements // 4, 5

Next, decide where you want your expensive operations to happen: on push or pop. Both removeLast() and append(value) are O(1) but insert(value, atIndex: n) and removeFirst() are O(`count`). Choose one cheap operation and one expensive operation.

public struct Queue<T> { 
    public private(set) var elements: Array<T> = []
    public mutating func push(value: T) { elements.append(value) } // O(1)
    public mutating func pop() -> T { return elements.removeFirst() } // O(`count`)
}

Guarding against Fatal Errors

At this point, you’ve now got a working queue. Unfortunately, there’s a major problem with this implementation. Calling `removeFirst` on an empty collection raises a fatal error. Oops.

Screen Shot 2016-03-08 at 12.26.57 PM

You can resolve this in several ways:

  1. Stick with the status quo and live dangerously (The “Russian Roulette queue”)
  2. You can make the queue throwing (ugh)
  3. You can make the return type optional (you have to test and unwrap)
  4. You can introduce an isEmpty property so you can test before popping.

I like option 4.

public struct Queue<T> { 
    public private(set) var elements: Array<T> = []
    public mutating func push(value: T) { elements.append(value) }
    public mutating func pop() -> T { return elements.removeFirst() }
    public var isEmpty: Bool { return elements.isEmpty }
}

Adding the property lets you guard your actions before applying any dangerous calls.

while !q.isEmpty { print(q.pop(), q.elements) }

Better Initialization

Structs offer free memberwise initialization, so you get an initializer for free that looks something like this:

var q = Queue(elements: [4, 5])

I find it more aesthetically pleasing to initialize using a standard array with inferred types:

var q: Queue<String> = [] // Queue<String>
var p: Queue = [1, 2, 3] // Queue<Int>

This behavior is courtesy of ArrayLiteralConvertible, and it’s really simple to implement. Just declare conformance and add an extra initializer:

/// A first-in/first-out queue of unconstrained size
/// - Complexity: push is O(1), pop is O(`count`)
public struct Queue<T>: ArrayLiteralConvertible {
    /// backing array store
    public private(set) var elements: Array<T> = []
 
    /// introduce a new element to the queue in O(1) time
    public mutating func push(value: T) { elements.append(value) }
 
    /// remove the front of the queue in O(`count` time
    public mutating func pop() -> T { return elements.removeFirst() }
 
    /// test whether the queue is empty
    public var isEmpty: Bool { return elements.isEmpty }
 
    /// queue size, computed property
    public var count: Int { return elements.count }
 
    /// offer `ArrayLiteralConvertible` support
    public init(arrayLiteral elements: T...) { self.elements = elements }
}

And there you have it, a simple, easy-to-use queue. If you want to adapt this implementation to a Stack, you get O(1) complexity for both push and pop operations using native Swift arrays.

Why I want build phases for Playgrounds

Dear Playground Team,

Right now, you can add a custom build phase to any Swift project so long as it’s not a playground. Custom build phases enables me to do all sorts of handy things with sources but most importantly, it lets me lint. Can you please add something like this to playgrounds?

While I’ve written my linter to be Playground-compatible from the command line, I’d much rather have a way to use the linter (and a spell/grammar checker for that matter) from inside the playground with highlighted yellow and red call-outs on the lines they apply to.

Sharing playgrounds is a top use-case, along with prototyping, exploration, etc. Being able to get those materials into shape with in-Xcode tools would really help. A lot.

Thanks,

— E

Swift Evolution acceptances: The big three

Today, Apple accepted (with some modifications) three major internally-driven proposals. They are:

Developed by the core Swift team, all three sculpt the way Swift defines itself as a language and how developers will express Swift conventionally moving forward.

The API Design Guidelines (SE-0023) leads off, establishing best practices guidance for Apple standard style. Most of this is pretty straight forward. Much of the advice is excellent. Some things I have small issues with. You as a developer are free to embrace as much or as little as you desire.

The automatic translation effort (SE-0005) has dropped its effort to strip NS from the start of API names (for the moment, a revised version will return as its own proposal).  It adopts the API guidelines in bringing Cocoa signatures into the Swift world. Get a sense of how these APIs will translate by visiting the review repository, which offers projections into Swift 2 and 3.

One significant part of the proposal was the removal of the “NS” prefix from Foundation APIs in Swift. This name change was considered problematic for several reasons, the most-often-cited one being that the reference-semantic nature of many Foundation types conflicted with the Swift standard library’s value-semantic types. The “NS” prefix removal part of this proposal has been removed from the accepted proposal. A revised version of this will come back as its own proposal, taking into account the feedback received.

Finally, the Standard Library update effort (SE-0006) establishes how Swift looks to itself, and how the methods in the standard library will conform to the recommendations in the new API guidance.

The proposed changes are massively source-breaking for Swift code, and will require a migrator to translate Swift 2 code into Swift 3 code. The API diffs from this proposal will be the primary source of the information about the required transformations. In addition, to the extent the language allows, the library will keep old names as unavailable symbols with a renamed annotation, that allows the compiler to produce good error messages and emit Fix-Its.

In accepting this proposal, Apple notes two important changes:

Most of the modifications to the proposal involve tracking changes to the Swift API Design Guidelines (SE-0023), especially:

  • Adoption of first argument labels throughout the Standard Library.
  • Lower-casing of enum case names, including “.some(x)” and “.none” for the all-important Optional type.

First-argument labels are something that have evolved first from Swift 1 to a more Objective-C like Swift 2 and now to a more Swift like Swift 3. They’ve reached a state that’s somewhere between pure C and pure Objective C, hopefully with a better balance than the previous two incarnations.

For example:

-  func advancedBy(n: Distance, limit: Self) -> Self
+  func advanced(by n: Distance, limit: Self) -> Self

-  func distanceTo(end: Self) -> Distance
+  func distance(to end: Self) -> Distance

Enumeration cases will now be treated like any other static members, and use consistent lower camel case naming.

An extensive diff list can be found in the updated proposal.

Like my posts? Consider buying a book or two. Thanks!

Survey: Help redesign Swift’s unused result system

Feedback greatly appreciated: [Survey Link]

Thanks in advance.

Beta 5: Embedding video in playgrounds

Beta 5’s new video feature enables you to create instructional embeddable videos that travel with your playground. Yes, this means your playgrounds are going to be quite large — there is, as yet (despite requests to the contrary), no support for linking YouTube videos.

What you do is this, you add movie files to the playground’s resources. You can then add specialized playground rich text:

//: ![Alternate text](video width="width" height="height" poster="poster")

You won’t see the video until you render the rich text. The video below shows a tiny tutorial playground I created that uses embedded video to introduce its content.

p.s. To create this example, I had to build a playground, video myself using that playground, then embed that video in a playground, and video myself using the playground with the embedded video. After a while, it was just playgroundception, if you know what I mean.

In which I learn to branch

Thanks, Joe Groff

  1. git clone your existing repo
  2. cd into the new clone
  3. git checkout -b NEWBRANCHNAME
  4. make your changes, edits, tweaks
  5. cd back to the primary clone folder top level (in the folder)
  6. git add .
  7. git commit -m "A meaningful commit statement"
  8. git push -u origin NEWBRANCHNAME
  9. Hop onto github and use the branch pop-up menu to select your branch
  10. Create your new pull request.

Optional step 11 is “hope you have not overwhelmed the team with your proposal backlog.”