Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts published in July, 2014

My first reading of the Swift books and of the generated Swift library header (remember, you can see the header by command-double-clicking on any Swift type) left me quite confused about the proper way to write generics and extensions to generics.

As usual, I favor learning-by-doing for such things [skydiving joke omitted] — I paged through a book on “Type Theory” to no avail — so, in a recent update to my SwiftChecker app I tried to include a useful extension.

Here is a (slightly edited) part of it:

public extension Dictionary {
	/**	Merges a sequence of values into a Dictionary by specifying
		a filter function. The filter function can return nil to filter
		out that item from the input Sequence, or return a (key,value)
		tuple to insert or change an item. In that case, value can be
		nil to remove the item for that key. */
	mutating func merge <T, S: SequenceType where S.Generator.Element == T>
		(seq: S, filter: (T) -> (Key, Value?)?) {
		var gen = seq.generate()
		while let t: T = gen.next() {
			if let (key: Key, value: Value?) = filter(t) {
				self[key] = value
			}
		}
	}
}	// end of Dictionary extension

To explain this, first recall that types can include typealias declarations within their definitions; this is much used for generic types, but can also be used everywhere. Here’s the declaration for Sequence from the library header:

protocol SequenceType : _Sequence_Type {
    typealias Generator : GeneratorType
    func generate() -> Generator
}

and of the GeneratorType protocol it uses:

protocol GeneratorType {
    typealias Element
    mutating func next() -> Element?
}

Going backwards: the GeneratorType protocol defines an associated type with the typealias declaration, in this case, Element. This is a placeholder type that will become an actual type when the protocol is adopted. These associated types form a hierarchy, so that you can refer to GeneratorType.Element and, further up, to Sequence.Generator.Element, and so forth.

Now look again at the merge method I define in my extension to Dictionary:

	mutating func merge <T, S: SequenceType where S.Generator.Element == T>
		(seq: S, filter: (T) -> (Key, Value?)?) { // ... etc.

Inside the <> after the method name are the type constraints. When I call merge on a Dictionary, this means that:

  • T is a placeholder type (with no constraints) used for the rest of the definition
  • S is another placeholder that is constrained to conform to the SequenceType protocol, and further (by using the where clause)
  • the generate() function for S must return a Generator whose Element is equal to T, and also
  • T is inferred from the argument type of the function/closure passed as the last argument to merge, and finally
  • this function/closure must return an Optional tuple of type (Key, Value?).

But what is this (Key, Value?) type, then? Recall that we’re extending Dictionary, so that type’s associated type hierarchy is also available; checking the declaration in the library header, we see:

struct Dictionary<Key : Hashable, Value> : CollectionType, DictionaryLiteralConvertible {
    typealias Element = (Key, Value)
    typealias Index = DictionaryIndex<Key, Value>
    ... etc.

so our type constraint will match Key and Value to those pertaining to the particular Dictionary that merge is being called on! To be more clear, we could even write (Dictionary.Key, Dictionary.Value?) in our definition.

Let’s look at a specific example of that. Notice that, where in the type constraints we refer to the placeholder type names (on the left of the typealias declarations), we refer to specific types wherever one is defined.

let strs = [ "10", "11", "12", "xyz" ]	// this is an Array  and therefore
					// its Generator.Element is String
let dict = [ 0:"0" ]	// this is a Dictionary <Int, String> and therefore
			// its Key is Int and Value is String
dict.merge (strs) { (s) in	// s is inferred to be strs's Generator.Element,
				// that is, a String
	let v = s.toInt()	// v is an Optional , will be nil for "xyz"
	return v ? (v!, s) : nil	// returns a valid tuple or nil
}
// dict will now contain [ 0:"0", 10:"10", 11:"11", 12:"12" ]

You can verify that everything matches our type constraints either directly or by type inference. If you change anything that doesn’t fit — say, by declaring s as anything but String inside the closure, or changing the type it returns — you’ll see a syntax error. (Assuming, of course, that no other extension has matching constraints.)

That said, currently (Xcode 6.0b5) the library header still has some bugs. Specifically, many type constraints either have too many prefixes removed, or show the wrong hierarchy, so you’ll see things like <S : Sequence where T == T> which won’t compile if you copy & paste it. No doubt this will be fixed soon.

Update: oops. Fixed the return, above.

Update#2: updated for Xcode 6.0b5 — many of those typenames either lost or gained a Type suffix.

A little over a month has passed since Swift came out, and I’ve just pushed a substantial update of my SwiftChecker app to GitHub. (Update: while writing this, I discovered a bug and pushed an updated update!)

While I still have to go back now and then to delete semicolons and to correct “String s” to “let s: String” (!@#$% muscle memory!) I finally can write out dozens of lines of Swift code without going back to the documentation or, worse, spend hours on the Internet checking why the compiler is balking. I suppose that means I’m assimilating the new syntax. It’s been over a decade since I had to learn a new language, so this isn’t too bad. 🙂

Looking at my new code, I’m particularly impressed by the conciseness of the language — the interaction with Cocoa APIs is still quite verbose, of course, but once I got used to type inference, the various map/filter/reduce/join functions, and of course generics, type extensions and operator declarations, I saw new ways of refactoring my code to be both more concise and more understandable.

In my almost 14 years of writing ObjC code I experimented with adding categories to existing classes but for the most part it always felt fragile and, after the initial experimental period, I went back writing subclasses or container classes. Using C macros to simplify stuff was tricky and error-prone. In Swift, by using generic types, it’s possible to write extensions and operators such that they don’t conflict with the existing implementation and this feels much more safe and natural. Although, of course, you still can unintentionally conflict with future additions to the Swift Library, namespaces should mostly take care of that.

Generics and type safety are a great help once I got used to them, which admittedly took some futzing around — the compiler is still very sensitive and the error messages are often cryptic or downright wrong. The type constraints and matching used for more complicated generics, admittedly, can become very complex — especially to someone not current on this new-fangled “type theory”. Still I was able to understand and build some simple generic extensions and functions that could be safely factored out into a few lines and greatly simplify other parts of my code.

Regarding optionals, I quickly got used to them; the old “returning nil” dance is now much less error-prone and at every step it’s clear which type is being handled and when it can be nil or not. The code is more readable in that regard, even if some nested “if let” statements have to remain when handling Cocoa return values. And ARC is practically transparent in Swift.

Speaking of values and ARC, the most troublesome parts are still those APIs — like the Security framework APIs I use in SwiftChecker — which haven’t yet been properly annotated. Certainly this will take many months, but no doubt pending updates to Clang will also take advantage of that, so that we’ll finally get rid of those pesky bridging casts.

One other positive side-effect is that the new whitespace rules, while mostly aligned with my own preferences, are finally making me insert spaces after commas, colons and around infix operators, and take other measures for increased readability.

All in all I’m very optimistic about Swift’s future. Can’t wait for the next Xcode beta to come out; the rumor mill says tomorrow, so let’s hope!

Well, finally I’ve decided to try out this newfangled GitHub stuff. Here’s my first repository: SwiftChecker, a simple real-world OS X app written in Swift. Quoting the readme file:

 My main intentions were to learn something about having parts in Swift and parts in ObjC; also to translate some of my experience with asynchronous execution to Swift. Since GCD and blocks/closures are already a part of system services and the C language (contrary to some people who claim they’re ObjC/Cocoa APIs), I found that it’s easy to call them from Swift either directly or with some small convenience wrappers.

The application displays a single window containing a table of running applications/processes (user space only).

For each process, it displays the icon, name and containing folder, as well as sandbox status (if present) and summaries for signing certificates (if present).

The table is not updated automatically, but there’s a refresh button to update it. A suggested exercise would be to listen to notifications for application start/stop and update the list dynamically.

Updating the table might potentially take some time if the system is very busy, since code signatures and icons will probably have to be loaded from disk. To speed this up, a simple “Future” class is implemented and used to perform these accesses asynchronously. In my timing tests, this accelerates table refresh by just under 4x — quite fair on a 4-core machine.

The project should build and run with no errors, warnings or crashes on OS X 10.10b3 and Xcode 6.0b3.

There are copious comments that, hopefully, explain some of the design decisions and workarounds where necessary.

I’ve also updated my previous post (Swift: a Simple Future) to incorporate some changes and simplifications I made during development of SwiftChecker. Check out the Future.swift file from the repository for a compilable file, with many comments.

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2024 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.