MMS • Sergio De Simone
In a recent article on Swift blog, Graphing Calculator‘s creator Ron Avitzur recounted how his decision to fully rewrite his app in Swift allowed him to shrink its codebase down to 30% of its original size, improving maintainability and readability while not losing performance.
Graphing Calculator is an app that makes it possible to create function graphs in two and three dimensions. Originally created in 1985, it was bundled by Apple with the original PowerPC computers, later moved on to live as an independent product available for macOS, Windows, and iOS. After 35 years of continued development, the best way forward, says Avitzur, was a full rewrite, although this is always a major feat, requiring a lot of work.
Legacy code embodies decades of hard-learned lessons […]. While a fresh start can be aesthetically satisfying, it creates an enormous surface area for bugs. In a typical dot release, focusing testing on new features is easy. With a complete rewrite, everything is new.
Graphing Calculator used a set of different languages and stacks, including C++ and Objective C/C++, Lex and YACC, AppKit and UIKit, and OpenGL. All of this morphed into a coherent Swift codebase using SwiftUI and Metal over 18 months with a reduction of the line count from 152,000 lines to 29,000.
Less code means less to debug, less to read and understand, and that alone makes the port easier to maintain. Using SwiftUI, view controllers go away entirely: a big win for declarative programming over imperative.
Among the major benefits of the rewrite, Avitzur mentions the reduction in boilerplate code, which made the logic and the meaning of code clearer; the use of value types in collection types, which made it simpler to reason about them; the conciseness brought by type inference, enumerations, closures, and Swift concurrency.
The biggest challenge, on the other hand, was keeping the same level of performance in comparison to a codebase which had been highly optimized for over 30 years.
As Avitzur explains in a Twitter thread, the first port paid a 10x penalty in terms of performance. He could reduce it down to 2x by disabling all Swift runtime checks and using vDSP for innermost loops. One remaining issue, though, is the cost of automatic reference counting on tree traversal, since the Swift compiler has no way to specify that a given portion of the code will not change any reference counts.
Overall, says Avitzur, both Swift and SwiftUI have lived up to their promises and opened up the possibility of contribute portions of the code in form of stand-alone Swift Packages for mathematical typesetting, editing, numeric and symbolic computation, and graphing.