Apps for which macOS applies compatibillity fixes
worthdoingbadly.com
worthdoingbadly.com
To take a wild guess, it could be a change from a stable to unstable sort: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
Apple gets a bad reputation for their supposed lack of backwards compatibility. Nothing is further from the truth: macOS includes tweaks for specific important apps to keep them working on new OS versions.
I read it more as "even Apple is willing to put in patches for backwards compatibility, if your app is important enough." If your app is not, then Apple couldn't care less. MS is more conservative about not breaking things even for relatively obscure apps.
Cocoa would not change from a stable sort, even if undocumented, to an unstable one. There's large compatibility risk and no benefit, since any app that is bound by sorting speed should do something custom anyways.
As to why the sorting hot fix: My first guess is that the app modifies the array from within the comparator. My second guess is that the comparator is not actually transitive, e.g. there can be "less than" cycles. In either case, Cocoa could work around this by employing a naive sorting algorithm.
However, relying on stability if it is not specified is a bad thing.
When possible, it would of course be best to use stdlib functionality, which would implicitly be cross-platform. Writing it yourself, or pulling in third-party libs to do it ranks way below stdlib, although I can't agree with myself whether doing so is better or worse than using OS-specific standard frameworks. Regardless, it is out of scope in this example.
Do you really think that when you sort a column in Excel, it puts the whole thing into a CFMutableArray and asks CoreFoundation to sort that?
Using CoreFoundation in such code is entirely sensible. Generalizing a sort for something like this would be a waste of time with no gains (as long as the functionality is used correctly, like not assuming a non-specified sort to be stable).
However, for the actual business logic, the hierarchy would be:
stdlib > large third-party cross-platform lib > small third party cross-platform lib ≈ homegrown implementation.There are dual-pivot quicksort, smooth sort (in-place, based on Leonardo numbers and takes O(n) time to process a presorted array and O(n log n) in the worst case, and achieves nearly-linear performance on many nearly-sorted inputs), TimSort (that's stable as plus).
Morealso changing stable to unstable sort is usually a very bad move.
That said, bubble sort is only n^2 and computers are fast. The real solution was that defrag was an alternative to crashing, so it didn't matter how long it took. Calling it meant a bug report needed to be filed.
The comparator here is "used" or "empty", where "used" is either > or < "empty".
So you wrote a non-compacting(copy)/generation garbage collector that used bubble sort?
In fact friends don't even let enemies use bubble sort, if they have an ounce of humanity.
Edit to actually answer the question: I wonder if it's something to do with some specific dataset having to be sorted in a particular way? i.e. where you'd normally use a stable sort, but the code accidentally depends on a specific unstable sort.
1. Excel needs stable sort but OSX sort is unstable.
2. Performance deoptimisation to make Excel perform worse.
2 occurred to me too, but surely that’s too cynical. It would make Macs look bad more than Excel itself.
Maybe it’s a bit of both. They needed a fix for 1, but they didn’t care about Excel performance at all so someone just spent 20 seconds doing a quick bodge job.
Mac Outlook on a recent MBP is noticeably slower (usability impact) than a similar version of Outlook on my Windows VM on the same machine against the same account (30k items, 5GB-ish)
(3 2 1) -> (2 3 1) -> (2 1 3) -> (1 2 3) (3 passes, 3 swaps)
Compare: (1 3 2) - > (1 2 3) (2 passes, 1 swap)
The iTerm2 one is interesting because it came too late. Apple's patch disables Sierra's native tabbing. Version 3.1.3 did not disable it completely. I published a fix in version 3.1.4 which came out on October 22, 2017, about a month after Sierra launched. I guess they must have fixed it in a dot release of Sierra, but I won the race and got the fix out before 10.12.1 which came out on October 27.
I'm glad someone's got my back, anyway.
I'll take 1px wide tabs over scrolling.
Which makes 1px Tabs annoying as hell.
So I really don't understand why 1px Tab is preferred over Scrolling Tabs.
Putting scrolling in a tab bar doesn't allow the user to take full advantage of spatial and muscle memories.
And when those memories fail, because scrolling tabs literally removes tabs from view, the user can't even revert to a visual search to find them! Instead one has to slowly scroll through a list of identically sized tabs, hoping that window #5 is actually the one containing the desired tab in the first place.
Oh dang, it was actually window #4.
Compare and contrast this to non-scrolling tabs, where tab size continually shrinks as tabs grow in number. #1 - you can identify which window is relevant by the tab sizes alone (so even if you move your windows around you're not lost). #2 - you can identify tabs by spatial memory, because you know approximately where, horizontally within the window, your tab exists, cutting your search space down to a few tabs only. #3 - you have visual cues as to when you might need to split out into a separate window for ease of tab management.
Of course, 1px is hyperbole, but 15px-30px is most certainly not, and on a modern display you can fit very many 30px tabs in a row without scrolling.
That's not to say that there aren't limitations to shrink-to-1px tabs, of course there are. But in all circumstances as a UI tool they are objectively better than scrolling tabs, until they shrink to an unusable size. At which point, scrolling tabs still isn't a good solution to the problem (grids, multiple rows, tab lists, tab groups are all vastly better options here).
Of course, if you don't have scrolling tabs then the tabs get so small that it's basically impossible to find what you want.
I solved this dilemma by hiding my FireFox tabs and using Tree Style Tabs. I find it really helps with keeping tabs organized and I can keep a lot open without worrying. I removed the scrollbar and close buttons, and made the tabs smaller, to further save on screen real estate.
On a Mac trackpad, this is one swipe. Sure, I see how this can be a problem if you use a scroll wheel, but I've never had this be a problem otherwise.
Relevant excerpt (abridged):
> I first heard about this from one of the developers of the hit game SimCity, who told me that there was a critical bug in his application: it used memory right after freeing it, a major no-no that happened to work OK on DOS ... the Windows developers ... added special code that checked if SimCity was running, and if it did, ran the memory allocator in a special mode in which you could still use memory after freeing it.
There are hundreds of special compatibility hacks for various software baked into Windows to make things run smoothly.
Edit: The links are broken now, but a paragraph from the article is quoted here:
https://www.joelonsoftware.com/2004/06/13/how-microsoft-lost...
> Look at the scenario from the customer’s standpoint. You bought programs X, Y and Z. You then upgraded to Windows XP. Your computer now crashes randomly, and program Z doesn’t work at all. You’re going to tell your friends, “Don’t upgrade to Windows XP. It crashes randomly, and it’s not compatible with program Z.” Are you going to debug your system to determine that program X is causing the crashes, and that program Z doesn’t work because it is using undocumented window messages? Of course not. You’re going to return the Windows XP box for a refund. (You bought programs X, Y, and Z some months ago. The 30-day return policy no longer applies to them. The only thing you can return is Windows XP.)
http://ptgmedia.pearsoncmg.com/images/9780321440303/samplech...
https://blogs.msdn.microsoft.com/oldnewthing/20031223-00/?p=...
https://www.joelonsoftware.com/2006/06/16/my-first-billg-rev...
It seems like he was good but not a spectacular programmer himself. Barbarians Led By Bill Gates is a great book about the relatively early days of Microsoft--early enough that the book describes some instances of programmers finding and replacing Bill's code with better stuff. IIRC there is at least one story of a new guy going "who wrote this crappy code" and then finding out it was Gates.
The major impact of software and computing was front-loaded, as in, it came with the early hanging fruits: being able to computerize banking, government data, credit card transactions, international trading, etc. This gave a huge boost to market efficiency and globalization.
The rest, with the internet, apps, online sales, etc, is just another outlet for doing business. Whether a 2B2 order happens on the web, or by old-style computer networks, or even by fax, is not that much of a difference.
Off the top of my head, credit cards and ATMs, and the purchase tracking and credit scoring agencies they enabled, have been a big deal since the 60s, says Wikipedia. (I would have guessed later!) Can't do that without a lot of software.
EDIT: Here's a list sorted by number of occurrences: https://gist.github.com/saagarjha/f36b6d99c3b89acfc02624806e...
It worked by injecting code into Finder at runtime, and then swapping method implementations for various classes. (Mac developers call this swizzling.)
We basically had to reverse engineer Finder every time Apple shipped a new version of MacOS. Later, as the process grew more common, we had to add tricks to make sure that we could work smoothly with other similar plugins.
I jumped for joy when Apple released the Finder Extension API!
Well, they definitely break a lot of things. Mostly things that were never documented or guaranteed to work, though.
My app [1] regularly broke with new macOS releases between 10.9 and 10.12. So often I actually shivered when they announced a new version.
I was calling Cocoa stuff from separate threads which is almost never guaranteed to work on macOS (the UI is explicitly not thread-safe). It usually worked on older releases though, but since 10.9 or so, it broke a little more with almost every new release.
Not really Apple's fault as it's mosty breaking stuff that was explicitly not guaranteed to work in the first place and which I shouldn't have used. On the other hand, Microsoft seems to keep every quirk from Windows 9x time still working until today.
It seems to me that you know what's wrong here, but just in case you don't, most UI work should be done on the main thread. There are certain lower-lever layer APIs that IIRC do explicitly allow for calls from multithreaded contexts, but other than that stick to the main thread. There's actually a new tool, the thread sanitizer, that helps you adhere to this by flagging all misuse of Cocoa outside the main thread.
> "Note that this is just a list of apps Apple has developed compatibility tweaks to make them run on newer macOS versions. As the list demonstrates, even the best apps often needs some tweaks on newer macOS. In addition, most of these patches are only applied to older versions of apps."
Quite a stretch from this to the clickbait title "These 299 macOS apps are so buggy...".
Also these apps are huge and push the platform forward more than other apps so the likelihood of this relying on undocumented behavior is much much higher and Apple is some sense shares responsibility for those bugs. So the face that they make these checkfixes makes sense.
While this can be good for performance and stability of these games, it does result in a bloated and complex driver, which I'm certain is difficult to maintain.
You do realize that the chances of this happening is next to nil, right? This is doubly true for prerelease software.
And if you aren't popular you can just goto WWDC where hundreds of engineers will quite happily talk through issues and give guidance on prerelease software.
You have to be really popular for this to happen, or be the only adopter of a technology they're trying to push. Basically, the question you have to ask yourself is "could Apple showcase us at a keynote?" Of course, such arrangements have massive NDAs around them.
> if you aren't popular you can just goto WWDC where hundreds of engineers will quite happily talk through issues and give guidance on prerelease software
Yes, but they aren't going to tell you what's wrong with your software…you'll need to go up to them at tell them "so and so doesn't work" and then they'll help you. I think it's unlikely that they'd just outright tell you that they made a special case for your software and you should get around to fixing it.
This it notable. It means Apple is ensuring backwards compatibility. Even if an updated version of your app (as detected by what OS it linked against) fixes things, these patches are still around for older versions of the app people may still be running.
Backwards compatibility never ages out...
I'm not sure what you mean, because to me that's what they're already doing, where the API version maps to the OS version.
When compiling in XCode, you can select which OS version you're targeting, and that essentially gives you which API version you're targeting.
Does it matter to a user if the change was due to some “buggy apps”? If it works, it works.
https://www.opera.com/docs/browserjs/
Edit: Even Chrome and Safari used to do it: https://dev.opera.com/blog/opera-s-site-patching/
They almost always break between MacOS releases. Usually the cause is that Apple improved various security restrictions in Gatekeeper. What tends to happen is that older builds work fine, but any new builds don't work well.
But, what's interesting is that the page at https://worthdoingbadly.com/assets/blog/appkitcompat/appkit_... doesn't list any bundle hashes. I always assumed that Apple's hacks for backwards compatibility were tied to the bundle hash, and not the specific application.
Why are they comparing an app version to an OS version?
Sometimes I do think software is doomed - like when a teammate of mine had to manually edit the bundled and minified javascript files right before release, because the bundler-crawler frankenstein code would've taken another eight hours to finish.
Putting an effort to make people believe the upgrading on macOS is smooth is important to avoid version spread like on other OS's.
I may have missed it in the article, but is the lookup run only upon first time the app is executed, or on every single run instance?
Based on the IDA disassembly, not much. A few extra CPU instructions has minimal impact generally.
> but is the lookup run only upon first time the app is executed, or on every single run instance?
It’s done every time the function in question is executed from what I can tell.
It also means that if some other developers want to make an app with the same kind of feature/behavior, they can't?
Some app developers also use special bundle IDs for testing...
I only see "no-go" reasons for such a thing, not a single valid or positive one!
Most app developers aren't going to spend resources putting out a dot release for years-old versions of their app. But users use those apps every day.
Check-fixed behavior is not a "feature," it's some sub-optimal behavior applied to work around serious bugs. An example is lying to the app about the OS version, to prevent the app from breaking. No developer wants to opt-into such behavior.
Note that check-fixes are tied to an SDK version, so when the developer switches to the newest SDK, they'll see the normal behavior.
Yeah, if you have an app that is used by millions of people, that is.
2) App vendor find out about the bug/issue and works around it, OR uses the API in a weird way that "works" but is non-compliant (see SimCity's use after free)
3) OS fixes the issue but then app breaks
4) Goto 1