Tag Archives: apple

Swift Types

If you look at the Swift Language guide, you get the distinct impression that the type system is sleek and modern. However the more you dig into it the more eccentricities you find.

The one I’m going to look at today makes sense only if you look at the problem domain from a slightly skewed perspective. I’ve been trying to think whether this is a sensible, pragmatic way of designing a language or a mistake. Judge for yourself.

So, the feature. Let’s define a dictionary:

var test1 = [ "Foo" : "Bar" ]

Check the type and we find that it’s of type Dictionary<String,String>. The generics and type inference are doing exactly what you’d image.

test1["Test"] = "Works"

So basically it’s all good.

So, what type is this expression?

var test2 = [:]

And why does this not work?

test2["Test"] = "Doesn't work"

Let’s take a step back. What’s the problem? Well, [:] is an empty dictionary but give us no clue what the type is. Remember, Swift dictionaries and arrays use generics, so the compiler only allows objects of a particular type to be added.

A good guess for the type would be Dictionary<AnyObject,AnyObject>. But a little fishing around tells you that’s not the case because AnyObject is neither “Hashable” or “Equatable” and keys need to be both.

The answer? test2 is an NSDictionary. That is, in this one circumstance, Swift extends outside its native dictionary type and decides to use a class found in Foundation.

Once you know that, it is clear that the second line should be:

test2.setValue("Does work now", forKey:"Test")

Maybe if you’re familiar with the guts of both Objective C and Swift this behaviour makes sense, but a language built-in returning a completely different type just because it can’t figure out the type feels broken to me.

In the end I think I’ve convinced myself that, while it might be convenient to allow this syntax, it’s a bad idea to saddle the language with these semantics so early on. In a few years when no one uses Objective C or when Swift is no longer fully tied to Cocoa, will this make sense?

I would prefer to see it being a compiler error with the correct approach being explicit with the type:

var test2:Dictionary<String,String> = [:]

Thoughts?

Swift Hate

I’m seeing a surprising amount of vitriol aimed at Swift, Apple’s new programming language for iOS and Mac development. I understand that there can be reasoned debate around the features (or lack thereof), syntax and even the necessity of it but there can be little doubt about the outcome: if you want to consider yourself an iOS developer, it’s a language that you will need to learn.

The only variable I can think of is when you learn it.

I think it’s perfectly reasonable to delay learning it as you have code to deliver now and because Swift is, well, very beta currently.

But asking what the point of Swift is not constructive. Asking what problems can be solved exclusively by Swift makes no sense at all you can do almost anything in most programming languages. Just because Intercal is Turing complete doesn’t mean that you’d want to use it for any real work. What varies between languages is what’s easy and what’s hard.

Objective-C undoubtedly makes some things easier than Swift. It’s a more dynamic language and its C foundations open up a lot of low-level optimisations that probably are not there in higher level languages.

But that same flexibility comes with a price: segmentation faults and memory leaks; pointers; easy-to-get-wrong switch statement; a lack of bounds checking. It also inherits a lot of ambiguity from original C language specification which makes certain automatic optimisations impossible.

How many applications require low-level optimisations more than safety? (And that’s ignoring that the biggest optimisations are usually found in designing a better algorithm or architecture.) How often is it better to have five lines of code instead of one? Every line is a liability, something that can go wrong, something that needs to be understood, tested and maintained.

Whatever its failings, it’s already clear that Swift is more concise and safer than Objective C.

There are absolutely applications where Objective C, C or C++ would be a better choice than Swift. It’s the old 80-20 rule applied to a programming language. And, for those resistant to learning a new language, the 80% is not on “your” side.

Right now, some of this requires a bit of a leap of faith. Swift clearly isn’t finished. You can either learn it now and potentially have some say on what the “final” version looks like, or you can learn it afterwards and just have to accept what’s there. But, either way, you’ll probably using it next year. Get used to it.

Learning Swift

Swift is a new programming language designed by Apple for development on OS X and iOS. I thought that I should try to learn it a little so I decided to convert a non-trivial collection of classes from one of my apps (www.cut) into Swift. I always find it better to work on a real project rather than just to play around with things aimlessly. Also, by re-working an old project, I knew that all the problems I would find would be language related rather than anything to do with the architecture.

The classes are also data related rather than being UI, so it is mostly a test of the language itself rather than how it interfaces with Objective C.

First impressions are good. Swift is mostly nice and consistent, which although sounding like damning with faint praise, is actually a compliment. I read a little of the language guide and dove straight in. A lot of the attempts to get the following right were me just typing stuff, guessing the syntax rather than looking it up.

Quite by accident I think my code sample inadvertently shows an area of strength for Objective-C and weakness for Swift.

The idea of the code is that it reads a Plist, instantiates a class based on that configuration and fills in a number of properties.

The first half of the code looks like this:

        NSError* error = nil;
        NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"XXX" ofType:@"plist"];
        NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
        NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListWithData:plistXML
                                                                                       options:NSPropertyListMutableContainersAndLeaves
                                                                                        format:NULL
                                                                                         error:&error];
        NSArray* values = [temp objectForKey:@"Entries"];

This was pretty straight forward to convert into Swift, though the type system gave me issues:

    let plistPath =  NSBundle.mainBundle().pathForResource("XXX", ofType: "plist")
    let plistXML = NSFileManager.defaultManager().contentsAtPath(plistPath)
    var error:NSError? = nil
    var format:CMutablePointer<NSPropertyListFormat>? = nil
    let immutable:NSPropertyListReadOptions = 0
    var pList = NSPropertyListSerialization.propertyListWithData(plistXML,
        options:NSPropertyListReadOptions(NSPropertyListMutabilityOptions.Immutable.toRaw()),
        format:format!,
        error: &error) as NSDictionary

Getting the options property seems very clumsy; I’m sure that there must be a better way of doing it.

I had a real problem with the in/out parameters format and error. Not only was the documentation confusing but the Swift Playground kept crashing making it difficult to distinguish between what I was doing wrong and where the compiler itself was messing up. It’s also a bit odd that, though both are in/out parameters, that they both need different methods to extract the values.

(To be fair, this is a beta and it is the first version of a whole language and compiler. I mention the crashes not because they’re unexpected or even especially bad, just as an honest description of the difficulty I had.)

The next section, using the data in the plist, was much more problematic. The code looks like this, but I’ve trimmed a lot so what we have here isn’t terribly useful now!

        proxy = nil;
        for (NSDictionary* i in values) {
            if ([thing isEqualToString:[i objectForKey:@"Class"]]) {
                dynamicClass = NSClassFromString([i objectForKey:@"BaseClass"]);
                proxy = [[dynamicClass alloc] init];
            }
        }

I didn’t do the straight conversion. A few more years of Cocoa programming allowed me to notice an optimisation:

    let valueList = values.filteredArrayUsingPredicate(NSPredicate(format: "Class = %@", value))
    let valueData = valueList[0] as NSDictionary

This same approach would work in Objective-C.

Next I tried:

  let dynamicClass = NSClassFromString(valueData["BaseClass"])
  let proxy = dynamicClass()

The first line works as expected. The second line doesn’t compile.

Is there anything else that we can do with dynamicClass? Let’s see. It’s an AnyClass which is a type alias for AnyObject.Type. Which doesn’t really help.

I tried casting it to a base class but no matter what I tried I couldn’t alloc/init it (in Objective C terms).

Josh Smith figured out how to do it by creating a factory class in Objective-C.

I tried (and failed) to get it to work by calling some of the Objective-C runtime directly:

var bytes:Byte[] = [0,0,0,0]
let b = objc_constructInstance(a, &bytes)

But the second line doesn’t work when using ARC. (To be fair, Xcode struck through the definition so I didn’t have much confidence that it would work!)

So that leaves Josh’s call out to Objective-C to be the best method that I’m aware of.

In the end I just used a switch statement to select between the relatively limited number of options that I had to choose between. Not as clever, but maybe that’s a good thing?

iTunes Match — addendum

Since I wrote about iTunes Match nearly eighteen months ago I thought it was worth revisiting and seeing how things have changed in that time.

Oddly, the short answer is “not very much.”

The problems that I identified last year are still very much present. Indeed there are some new examples. This is my favourite: when listening to “Man Machine” by Kraftwerk, iTunes Match seems to have decided that track four, which should be “The Model,” is really “Wouldn’t it be nice” by the Beach Boys. I don’t even own a copy of “Wouldn’t it be nice.”

The biggest changes in those eighteen months have been on the client side. iTunes 11 (the lipstick on pig release), as far as I can tell, didn’t change very much. iOS 6 wasn’t nearly as fortunate. The point zero release removed the ability to delete individual tracks. Not exactly progress. (It’s back again in 6.1.)

Apple likes to talk about its magical products that Just Work. iTunes Match tries to be more magical than most but clearly missed a few visits from the faeries.

One bit of magic that I thought was supposed to happen was that when getting low on disk space, iTunes Match would delete less played tracks. In fact, what I think happens is that it removes older, cached tracks.

The distinction here is between cached and downloaded. If you press the download (cloud) icon it isn’t automatically removed; if you didn’t it is.

But how do you tell? Well, that’s the other major client flaw. There’s no easy way to see which tracks have been downloaded without opening each album, one by one. I have six hundred albums which makes this an exceedingly tedious task.

My guess is that you’re supposed to use it by just pressing the Play button and have iOS manage the space for you. But this would mean you live in a utopian universe where you have a data signal every time you want to play some music. That does not resemble my life.

What I want it to be able to download tracks that I think I’ll want to listen to and then allow playing from the cloud. When low on space it should remove tracks that have not been played recently regardless of how they got there.

So eighteen months on I find that many of the same problems remain and I’ve found some new ones, yet I still paid for another years subscription without much though. Why? Well, it’s still very useful. I like being able to play music using my Apple TV. I like being able to access any of my music when I have wifi or 3G. I just wish Apple would spend a little time and make it less like a 1.0 release1.

  1. You could argue that they added iTunes Radio, but that only comes with iOS 7 — nearly two years after iTunes Match came out — which isn’t out yet and even then that will only work in the US to start with. []

War?

Eric Schmidt says Google is the new Microsoft and it’s winning the war against Apple. I think he’s missing some perspective.

One of the key things that Steve Jobs realised when he returned to Apple in the late nineties was that the industry is not necessarily a zero sum game.

We have to let go of a few things here. We have to let go of the notion that for Apple to win, Microsoft has to lose.

The current situation is not identical but I think that the lessons might be substantially the same. While Google believe that they’re winning it’s not clear to me that they’re playing the same game as Apple and Microsoft. It’s like saying that you’re winning at Scrabble when your opponent is playing Chess; sure, you played some great words on triple letter scores, but your chances of getting check-mate are limited.

For all Google’s efforts and marketshare, most web traffic and ad impressions — the real metric that they’re interested in — still comes from iOS. They largely succeeded in commoditising the smartphone, unfortunately their users either don’t surf the web much or, in the case of Android-derived devices like the Kindle Fire, do but don’t go via Google.

Would they not be better toning down the rhetoric and figuring out how everyone can play nicely? War makes for good headlines but often ends in everyone losing.

For Google to win, Apple does not have to lose.

iTunes Match

It seems that there’s a large variation in people’s experience with iCloud and iTunes Match, Apple’s recently introduced service for making your entire music collection available across all your devices. At the risk of making things worse — since I have nothing conclusive to add — I thought that I’d add my anecdote to the collection.

Like most software — and especially Apples — it works best when you work in a particular way. It’s often difficult to tell how close your expectations are to the real thing until after you’ve handed over your credit card. But what I will say is that iTunes Match works pretty well if you want to do what I do. So if you read nothing else in this post, you should look at the next few paragraphs.

What do I want to use it for?

I have about six hundred albums, comprising over six thousand tracks. I mostly listen to a smaller subset but I often get an ear-worm and want to listen to a random track that I may not have heard for years. So on my iPhone I have a lot of music, but not all of it. Use case one for iTunes Match was therefore to be able to access all my music on my iPhone even though I don’t have the space for everything.

I typically don’t put any music at all on my iPad, since I use it more for movies than music. But when I’m travelling it’s occasionally nice to be able to rely on my iPads battery as well as my iPhones! So use case two is playing music on my iPad without explicitly copying any onto it.

(These last two are clearly variations on a theme, but the key point is that I don’t want to have to stream everything. When I’m at work I don’t always have internet access, but I can probably get WiFi access for a few minutes at lunchtime.)

Ten years ago I spent a lot of time ripping my CD collection. Most is in MP3 format at 160kbps, some is at 128kbps; the newer ones are reasonable quality AAC but, if I’m honest, there’s little consistency. Additionally, many tracks are of dubious quality, with dust and scratches contributing most of the glitches. So, use case three is upgrading my library to clean, high bit rate copies.

How does it work in practice?

The process is typically Apple, by which I mean works without very much user intervention and pretty smoothly.

It first scans your library, sees what’s already in the iTunes Store and then uploads any gaps. The scanning and matching is really quick. The upload depends on the speed of your broadband.

It matched around 5000 of my 6000 tracks, which is not bad going. However there were some oddities:

  • It was very inconsistent with spoken word tracks. I have a number of radio series — the Hitchhikers Guide and a bunch of Douglas Adams interviews, the Mighty Boosh — and some tracks were flagged as “Ineligible” while others were going to be uploaded
  • Some tracks that I purchased from iTunes a while ago were not matched
  • Some albums were only partially matched, despite the full album being available to purchase

The common element is that it’s not at all clear what criteria are used to make the match. Either Lala wasn’t quite as sophisticated as I thought or Apple have not fully integrated their software yet.

Whether these are problems or not depends entirely on what you want to do with the tracks. That the spoken word albums are (mostly) unavailable is slightly disappointing but not really a problem.

The iTunes tracks not being matched is, frankly, bizarre. Here you can see one track from an album “Purchased,” one “Duplicate” (it isn’t) and the rest were uploaded (i.e., not matched and a copy from my library uploaded to iCloud).

Still, neither of these issues stops all my music being available on all my devices — use cases one and two.

However the last point above is disappointing. Some albums match every track bar one or two. This means that it’s not possible for me to upgrade the whole album to a 256kbps AAC file. Not the end of the world but not exactly what I was promised.

In use

iTunes Match is mostly pretty seamless. You see all your music on all your devices. If the track hasn’t been downloaded, it appears with a cloud symbol next to the name. Click or press on the track and it plays, albeit with a short delay. iOS clients download rather than stream the content. The Apple TV just streams the music and videos.

Two surprisingly un-Apple-like glitches take the edge off the whole thing.

Firstly, not all the album art work makes it from my iTunes library to my iPad and iPhone. It’s a small point, but for a company that places so much emphasis on the aesthetics it’s unexpected.

Secondly, while it is possible to upgrade your low quality MP3 files it’s not entirely clear how to go about it. I guess I expected to see an “Upgrade track” or “Upgrade Library” or even a “Update to iTunes Match” menu option, but no.

I couldn’t see anything in the documentation either. I had to fall back on Google. The trick, it turns out, is to delete the file. Obvious, no? Then iTunes will show the same track but with a cloud icon to the right. Then you can download it.

Conclusions

So, overall, I like iTunes Match. It’s not without flaws, it’s undoubtedly a 1.0 release, but it’s already useful to me and I think it’s only going to get better. I guess the big question comes at the time next year. Will I renew the service?