What has Happened to Swift?
Thursday, June 28th, 2018As a long-time fan of ObjC, and what NeXT and Apple have done with it, I was very interested when they released Swift 1.0 back in 2014, I was excited to see them move a little in the direction of Ruby. Everything in one file, more along the lines of a semi-scripting language, and while it wasn't complete to be sure, I was impressed that Apple was moving in this direction.
This week, I've been working on some architecture docs for work, and one of them is about the mobile platform space, and what we should be doing there to really increase the stability and speed of feature releases. Something that's been historically tough for NeXTSTEP and Apple with regards to ObjC is memory management and threading.
The days of retain/release were somewhat tough for new developers to ObjC to get right. It was really just about understanding the patterns for the use of retain and release and when to use autorelease. Once you had those down, you were pretty much golden. The run loop would pick up the instances with a retain count of zero, and didn't have to go looking for them. Memory didn't grow unless you retain-ed it and that was then pretty easy to spot with something like OmniAlloc.
Then Apple added Automatic Reference Counting and it got a little better, but we lost a few things in the mix. For example, compare-and-swap operations could not be known to have succeeded or failed by the compiler, so it could not know what to do with the retain count. I understood this, but ARC, as it was known, did a lot about removing the need for retain/release and so it got folks up to speed faster.
Losing a little functionality is something I can understand - if the overall gains are there, and there is at least some possibility of implementing similar functionality another way. This was disappointing, and Apple was clearly forcing ARC on the developers, as they had warnings about the use of retain and release.
Then I didn't pay a lot of attention to Swift 2 and 3, but I had reason to look at Swift 4 because of these architecture docs for the mobile platform. Wow. Apple has gone crazy and complex with Swift 4.
Several things have been added in 4.0 that wasn't in 1.0 - and some of them are probably quite nice. But at this point, the costs don't seem to outweigh the complexity of the language. But it certainly explains the Playgrounds as a concept - to get people writing code in a more friendly, less stressful environment.
Swift has lost the ability to use classic threading concepts like pthreads, and mutexes, and put in their place Grand Central Dispatch (GCD), which is a great idea for the kinds of "work unit" things that end up really complicating the code base when you have to do lots of different things - like most apps these days. But it shouldn't be used for little things... it's just too much overhead.
At least that's how tools should be used. You don't use a hand grenade to kill a mosquito, and you don't need Grand Central Dispatch to atomically increment an integer... or do you?
Yet that's what I was to come to learn from the docs I was reading. Apple is really pushing the concept of the main thread of the app, and that makes sense - it is the hold-over from the run-loop, and the single-threaded nature of classic Mac apps. This is a lot like the run loop of X11 apps, and a lot of the UI apps for a long time. But then why not abstract that thread from the programming model?
But there's more...
Because of the dynamic relocation of memory in iOS, there really can't be any fixed memory locations in the code. It's a cool feature, but now you have to add all the things in the language to indicate mutability and access control. They could have used this syntax to indicate which variables are to be fixed... or at least tracked carefully so that they always appear to have a stable location in the memory map of the process.
The end result is that Swift has become quite limiting in how to do things. You really have to go all in with their constructs. That would be fine if they had taken the extra steps and built in that level of abstraction. If they wanted Grand Central to play such an important role, then hide that role with some simple syntax. Make the 'jobs' that go onto the GCD queue simple and allow their specification to indicate their need for thread safety.
When I re-wrote some code from ObjC to Ruby, the project went from 2,700 lines to about 790. That's a significant savings, and makes code easier to write, maintain, and enhance. That's good stuff. But with the things that I'm seeing now in Swift 4 - I would not be surprised if the reduction to Swift wasn't at all like that for Ruby. I hadn't done the conversion at the time because Swift 1.0 didn't have the kinds of class libraries that I needed to make the conversion. Now, it probably does.
Some day I'll actually have to knuckle down and write the project in Swift and see what it turns out to be. I hope this is just a step along the way for Swift... just a snapshot of where they want to go.