Math with Roman Numerals

I’ve been reading (listening to, actually) a book on the state of scientific and technical knowledge in what has traditionally been referred to as the “Dark Ages” (roughly the 5th to 14th centuries). One of the things I became intrigued by was the use of Roman numerals for relatively complex math during this period.

Quick Review

You’re probably familiar with Roman numerals. Conceptually, they’re easy. Letters represent numbers. To get the value of a number written in Roman numerals you simply add the individual numerals (or groups of numerals). Here are the letters you use to represent values up to 3999:

I = 1
V = 5
X = 10
L = 50
C = 100
D = 500
M = 1000

Values are read from left to right, and it is traditional to put the larger numerals first. So III is 3, XII is 12, and DCLXVI is 666 (“let the reader understand”). One complication is that you never write the same numeral more than 3 times in a row, and that a smaller numeral appearing before a larger one means it should be subtracted from the larger value. So 14 is XIV, not XIIII. 3999 is MMMCMXCIX. That being said, the Romans weren’t real picky about how these numbers were written. For simplicity, I’m going to ignore the no-more-than-3 rule from time to time in my discussion below.

I’ll use the symbol => to indicate that I’m rearranging or simplifying.

Adding and Subtracting

Addition with Roman numerals is easy: just put all the numerals in one group and rearrange them. So III + XVIII is IIIXVIII => XVIIIIII => XVVI => XXI.

Subtraction is similar. Convert larger digits into groups of smaller ones if needed for convenience, then just subtract similar numerals from each other. So XXI – III is XVVI – III, which is XVIIIIII – III, or XVIII.

Doubling and Halving

Before getting into the fun stuff (multiplication and division), it helps to think about how to double and halve a value written in Roman numerals.

Doubling is just adding the number to itself. To double a number, just write two of each numeral. Twice XXI is thus XXIXXI => XXXXII => XLII. Twice III is IIIIII => VI.

Halving is similar. Divide each numeral by 2 and append the next lesser numeral if there is a remainder. This is slightly circular, since we’re saying to divide by 2 you divide by 2. If you don’t remember what half of L is, write it out as XXXXX and take half of those X’s to get XX with a remainder of half an X, which is V. To get half of 666, follow these steps:

DCLXVI
CCL + half of CLXVI
CCL + L + half of LXVI
CCL + L + XXV + half of XVI
CCL + L + XXV + V + half of VI
CCL + L + XXV + V + II + half of II
CCL + L + XXV + V + II + I
CCLLXXVVIII
=> CCCXXXIII

Multiplication

Multiplication is a combination of doubling, halving, and adding remainders. Note that in general A ✖️ B is the same as (A / 2) ✖️ (B ✖️ 2). That is, if we double one term and halve the other term, the result is the same. In familiar terms, 8 ✖️ 3 (24) is the same as half 8 (4) times twice 3 (6). Further note that we can do that again, so:

8 ✖️ 3 = 4 ✖️ 6 = 2 ✖️ 12 = 1 ✖️ 24 = 24

Where it gets tricky with Roman numerals is handling remainders. Consider if we reversed which term was being doubled and which halved in our example above:

8 ✖️ 3 = 16 ✖️ 1.5 = 32 ✖️ .75 ….

While the first attempt actually took us all the way to the correct answer, the second appears to be getting harder and harder. Let’s look at both with Roman numerals:

Half
VIII
IIII
II
I

Double
III
VI
XII
XXIIII => XXIV

When the halving leaves a remainder, we can ignore it. I’ll mark those with an asterisk.


* drop remainder

Half
III
I

Double
VIII
XIIIIII => XVI

When we have remainders, there’s one more step. We need to add the value from the “double” column to our final result to get our true result (since we technically dropped that value when we dropped the remainder):

XVI + VIII = XVVIIII => XXIIII => XXIV

We can apply this technique to do arbitrarily complicated multiplication:

39 ✖️ 81


* drop remainder
* drop remainder
* drop remainder
* drop remainder

Half
XXXVIIII
XVIIII
VIIII
IIII
II
I

Double
LXXXI
CLXII
CCCXXIIII
DCXXXXVIII
MCCLXXXXVI
MMDLXXXXII

Now add the value from the “double” column for each odd value in the “half” column.

MMDLXXXXII + LXXXI + CLXII + CCCXXIIII = MMDCCCCLLLXXXXXXXXXXIIIIIIIII => MMMLLLVIIII => MMMCLIX

I’ll leave it to the reader to verify my work.

Division

I’m not sure if there’s an easier way to do vision, but here’s what I came up with. First, we repeatedly double the divisor (the number by which we’re dividing) until we get a value greater than the dividend (the number that we’re dividing). We’ll keep track of the multiplier for each because we’ll need those later.

Consider 365 / 12

In Roman numerals: CCCLXV / XII

Multiplier
I
II
IV
VIII
XVI
XXXII

Double
XII
XXIV
XXXXVIII
LXXXXVI
CLXXXXII
XXXLXXXIV







exceeds dividend

We now know that XII goes into CCCLXV at least XVI times. We can make a note of that, and also subtract the doubled divisor to see what’s left:

CCCLXV – CLXXXXII = CCLLXXXXXXIIIII – CLXXXXII = CLXXIII
XII goes into CCCLXV XVI times with a remainder of CLXXIII

Now check our list of doubled divisors to see what the biggest one is that goes into the remainder (CLXXIII). It looks like LXXXXVI is the largest value that is smaller than CLXXIII. Repeat the step above. Subtract LXXXXVI from our remainder and add the multiplier to our accumulated multiplier:

CLXXIII – LXXXXVI = LLXXXXXXVVIII – LXXXXVI = LXXVII
XII goes into CCLXV XXIV times with a remainder of LXXVII

Repeating, this time using a multipler of IV and a doubled divisor of XXXXVIII:

LXXVII – XXXXVIII = XXXXXXVVIIIIIII – XXXXVIII = XXVIIII => XXIX
XII goes into CCLXV XXVIII times with a remainder of XXIX

Repeating, this time using a multiplier of II and doubled divisor XXIV:

XXVIIII – XXIIII = V
XII goes into CCLXV XXX times with a remainder of V.

Since V is less than our original divisor, that’s as far as we can go.

Again, the proof is left to the reader.

Fractions

I’m not going to dwell on fractions except to say that the only fractions the Romans seemed to use were twelfths and halves. Each twelfth was a dot following the number. Since we coincidentally divided by 12 in the previous example, our remainder of 5 would be represented as 5 dots following XXX. I believe they were written in some kind of pattern, perhaps like we use on dice or playing cards.

Halves were represented using the letter S. So 7/12 would be “S..” or maybe “S:”.

Conclusion

While this is fun, and while our Middle Ages ancestors could do amazing things using these simple techniques, it’s pretty clear why the hard math was being done using base-10 and place value representation.

Working Without a Net

In 1988 we took our kids to Circus World in Baraboo, WI. We had the good fortune to see Enrico and Debbie Wallenda performing on the high wire. The crowd was small, so we had a chance to chat with them after the show.

I noticed that, while they performed without a safety net, they had laid out some tumbling mats under the wire, which was some 20-30 feet in the air. “Why bother with the mats?” I asked Debbie. “Our insurance company won’t let us perform without safety equipment,” she said.

2015-06-04 07.57.00Enrico and Debbie come from a family of circus performers that goes back to the 17th century. They grew up on the wire. They know what they’re doing. The safety net is unnecessary. It would just slow down their set-up and be one more thing they’d have to carry from show to show. And it would be an insult to them. Amateurs need and use safety nets. The Wallendas just don’t fall.

Well, they do, but no more than once each.

I’ve been programming since about 1974 and doing it professionally since 1982. I remember my ham radio buddies talking about these cool new things called “microprocessors” in 1972, and was actively programming for them through the entire history of the “personal computer revolution”. I wrote a machine language debugger for the Motorola 6502 just for fun back in the early 80’s. I was working with touch screens in 1982 while the company that would eventually put one on an iPhone was just beginning to experiment with mice and graphical user interfaces.  I wrote drivers that allowed CP/M systems to store data on “magnetic bubbles” that raced along a track driven by an electromagnet. I was writing code to calculate position using GPS when there were only about 8 GPS satellites in orbit and we had to calculate what ridiculous time of the morning we’d have to come in when we would be able to see the required minimum of three of them at the same time for testing our software.

Over the years I’ve programmed in assembly language, Pascal, PL/I, Modula 2, FORTRAN, COBOL, SNOBOL, LISP, BASIC, RATFOR, C, Forth, JOVIAL, Ada, C++, NewtonScript, PHP, Objective-C/C++, Perl, Java, JavaScript, C#, and VBScript. I’ve written a number of compilers and interpreters for lesser-known and proprietary languages. I’ve written programs for Atari, CP/M, MS-DOS, VMS, Windows (desktop and server), Mac OS and OS X, Newton OS, various flavors of Unix, Windows CE, Palm OS, Android, and iOS.

When I’m making updates to the scripts and pages on our Laridian website, I operate directly on the live server. From time to time that means if you happen to be on the page I’m on when I make a mistake, you’ll see an error message when you load the page. But that happens only rarely. When working on a critical part of e-commerce code, I might test on a private page before going public, but often that isn’t practical.

Running a beta testing program with outside testers, especially for a platform like iOS (which requires encrypting the app in a particular way that allows only selected devices to run the program), is difficult and time-consuming. So most of the updates I do for Mac and iOS programs are just tested by me before they are shipped. Often, I’m a better tester than real customers, because I know the scope of the changes I’ve made to the code, and I know where it is susceptible to error. For example, all the testing of synchronization of user data was done in-house. I was able to set up both common and unusual situations to verify how the system would handle the data without putting any real customer data at risk. When the time came to put that system online, it just went online without any beta testing.

So I sympathize with the Wallendas. That safety net takes a lot of time to set up. We know we’re not going to fall. And it takes away from the perception of professionalism — anybody can walk a tightrope when there is no harm in falling.

But when we fall, we fall hard.

Last weekend I shipped an update to PocketBible for iOS that was not tested by outside testers. The majority of the changes were to accommodate the larger screen of the iPhone 6 and 6 Plus. I have an iPhone 6, and I can emulate the 6 Plus in the development environment. Those changes were well-tested.

The other type of changes were related to what happens when you change the password on your Laridian account. Previous versions of the program assumed you were logging into a new account when you entered a different password, so they blocked you from sync’ing your notes, highlights, and bookmarks with the server (so as not to corrupt the “other” account’s existing data, nor corrupt the data on the device with data from the “other” user). Furthermore, they would delete all your books (assuming, again, that you are a different user with a different library of books). The new version of the program records the Laridian customer ID you’re using while sync’ing your database with the server, and only complains about your user data if, when changing your password, you log into a different customer account. Furthermore, it doesn’t delete your books. (I plan to handle that a different way in future releases.)

So while testing the screen-size changes on the iPhone 6, I also tested the new way of determining if you had logged into a different account. It worked great. What I didn’t count on was that Apple had completely changed the way certain user interface objects worked on the iPad sometime in the year since I had issued the last PocketBible revision. As a result, iPad users couldn’t update their data to support the new customer ID tracking method. My testing on the iPad consisted of bringing the program up and trying a few things to make sure it wasn’t completely broken. Since the bulk of my changes were related to laying out the user interface on the larger iPhones, my testing focussed on making sure I didn’t break any layout code on the iPad. I already knew the customer ID tracking worked from my tests on the iPhone.

I joked with one long-time PocketBible customer that I didn’t want to take time to do a beta because I knew he would find problems that I would have to fix. So I shipped version 3.2.0 without the benefit of his help.

Once Apple approved the new version and I installed it on my iPad and saw what was happening, I knew I was in trouble. I began thinking about how those tumbling mats were going to feel when struck from this height.

When Karl Wallenda fell to his death from 120 feet, the family went ahead with their show the following weekend. That’s what professionals do. In my case, I admitted to the mistake immediately, pulled the app from the App Store, posted prominent notices on our blog and on Facebook, and went to work to find the problem. By 2 AM I had the first round of fixes made to the code. After a short nap, I found and fixed the rest of the problems (which required examining about 300 places in the code) and was ready for beta testing by mid-afternoon. We went through three beta versions in 24 hours, and I didn’t upload the final build to Apple until I had a clean bill of health from the testers.

Apple cooperated by approving my request for expedited review, and accomplishing that review within an hour.

In the end I was able to stand up and walk off the mats under my own power. The fans were great; they encouraged me by applauding through the whole thing. I was concerned that some would want their money back, but I got not a single complaint.

While I probably won’t be shopping for a safety net, I may consider doubling the mats.

VBScript/Classic ASP Function Parameters

I know that VBScript passes parameters by reference, but I seldom take advantage of that feature. So when I need it, I am always able to convince myself that I’m misremembering. So here are the results of a recent test to remind me:

function Three(N)
	N = 3
	Three = 0
end function

dim x
x = 1
Response.Write "<p>x = " & x & "; Three(x) = " & Three(x) & "; x = " & x & "</p>" & vbCrLf

Output:

x = 1; Three(x) = 0; x = 3

Advancing Technology by Lying to Developers

Mobile devices have been increasing in screen size, screen resolution, memory, and other capabilities on a continuous basis from the time I got my first Apple Newton MessagePad in 1993. Back then screens were about 336×240 pixels, and each pixel was either on or off — no color. There was a total of 4.625 MB (that’s MEGA bytes) of memory. My first Windows CE device was probably my HP 620 LX in 1998. It was a “clamshell” design with a 640×240 screen and 16 MB of memory.

The thing we knew intuitively from being involved in personal computing since there was such a thing as personal computing was that “change is the status quo”. Our programs never assumed how big the screen was, because we knew our program would need to run next week on a bigger screen, so we wrote our code so that it queried the operating system to ask how big the screen was before dynamically laying out its user interface to fill all available pixels. We never assumed that devices would always be monochromatic, so we wrote our compressed file format to accommodate “words of Christ in red” before they could even be displayed in anything but black on a greenish screen. And even though the entire Bible wouldn’t fit in memory of those first devices, we plowed ahead with the best compression we could manage and a user interface that supported displaying two Bibles simultaneously, knowing that very soon you’d be able to get not just one of our Bibles but two whole Bibles onto the device at the same time.

Fast forward to the iPhone in 2007. When you work for Apple you apparently get big-headed and begin to think you’re among the smartest programmers in the world. Nobody can match your brilliance. Each generation of device you work on is “magical”. It has capabilities and features that nobody could have imagined even six months ago. Features like a more memory and a bigger screen.

Since you couldn’t imagine those features last year, and since you’re God’s gift to technology, you’re positive that nobody else could have imagined those features. So what’s going to happen to all those apps written by people “too dumb to work at Apple” when your new device with a bigger screen comes out? Why, they’ll crash, of course.

Not PocketBible.

You only have to be in this business a week to realize that you can’t hard-code your program to assume a particular screen size. But Apple does this with every single device. Up until iOS 8, we had to prepare a “splash image” to display when the program launched in every possible size and resolution. Currently, that means we have to create launch images in 13 different sizes, one for each iPhone screen size that has ever been shipped, in both portrait and landscape orientation.

Current iOS launch image requirements

Current iOS launch image requirements


If instead they allowed us to manipulate a single image at run-time, we could do all of these with one PNG. But they require us to know every size of every screen we might ever run on (by the way, the image above omits devices prior to the iPhone 4, which would add another half-dozen sizes if they hadn’t already been abandoned by Apple).

This isn’t about managing lots of images. It’s about a philosophy that can’t think past yesterday.

Because of this philosophy, when a bigger screen comes out, Apple either “letterboxes” old apps (putting black bars in the empty space that the program couldn’t possibly imagine would ever be there) or scales them (allowing them to believe the screen is no bigger than last year’s device, then scaling up everything they draw to fill the bigger screen). They believe they are saving developers from having to re-release their apps every time a new device comes out. But in reality, they are requiring every developer to re-release their app to jump through whatever hoop is required to get Apple to stop letterboxing or scaling their apps.

iPhone 6 scaling

Pre-iPhone 6 version of PocketBible on the left gets scaled up. Adding a “launch screen” (which is unrelated to drawing text) tells iOS not to lie to us about the screen size, producing the sharper image on the left with absolutely no changes to PocketBible code!


With iOS 7, there was a special checkbox we had to check to tell the OS that we understood their new semi-transparent user interface elements. With iOS 8, in order to convince iOS not to scale your app (producing blurry text), you have to provide a special, scalable launch image that works on any screen size. (Gee whiz, 2015 and we’re finally recognizing that screens might get bigger in the future! Thanks, Apple!) Until you do that (which requires re-releasing your app), iOS will lie to you about the size of the screen then scale your user interface up to the bigger physical size of the screen, producing blurry text.

Oh, and you still have to provide those 13 launch images for older devices.

The result of this policy of “technical advancement by lying to developers” is that instead of one guy at Apple having to write zero lines of new code, hundreds of thousands of developers have to update and re-release their apps. There would not have been a personal computing revolution in the 80’s and 90’s if Microsoft would have taken this approach. Back then, Microsoft would collect commercial software products and use them for regression testing of new versions of DOS and Windows. After all, you wouldn’t want to do something stupid and break every single app the way Apple does with every release of the iPhone.

This industry used to be exciting. I was like a kid in a candy shop. Technology was changing and we were riding the “bleeding edge”. Now I feel like the only grown up in the room. I want to slap some of these Apple and Google kids around and tell them to shape up.

Delete Program Preferences in OS X (Including Cache)

Often while debugging an app it’s handy to delete its preferences so it will “start over” like a fresh install. You used to be able to find the .plist file in the Preferences folder and delete it. Simple.

Starting with OS X 10.9, preferences are cached. So even after deleting them, they’re still around. Here’s the magic shell command that deletes them:

defaults delete com.company.programName

Why I Don’t Care About Swift

Swift is a new programming language created by Apple for use on OS X and iOS devices. The programming world is agog. Apple’s fantastic new language apparently solves all their problems, as evidenced, they say, by the fact that some programmer ported Flappy Birds to it in a few hours.

I’ve been around long enough to see languages come and go. Each claimed to solve all the problems introduced by its predecessors, yet each was replaced by a language that solved all its problems. In some cases, the new language surpassed the success of the language it replaced (C++ and Java); in other cases, the new language faded into obscurity (Modula-2 and Ada).

Lately the motivations for new languages have been dubious. There is a big emphasis on making a language easy to learn and having it hide nasty issues related to memory management and type safety. One review of Swift I read stated, “Apple hopes to make the language more approachable, and hence encourage a new group of self-taught programmers”. While that sounds great, it means that those of us who have mastered our craft after 30 years or more of practice are saddled with the training wheels and water wings that are written into these languages for the noobs.

A classic example is the lack of unsigned integers in Java. The motivation for this was to simplify the language for “new and self-taught programmers” by avoiding errors caused by a lack of understanding of sign-extension. However, for those of us who showed up for class the day that sign extension was taught (that would be day two), we’re left with a language that unnecessarily limits the range of positive integers and requires us to actually have mastered sign extension in order to understand what is happening when we directly manipulate the bits in our integer variables.

Explicit vs. Implicit Typing

One of the simplifications Swift makes is that it infers the types of variables from the values assigned to them rather than requiring the programmer to explicitly type variables. If this was true “weak typing” like I’m familiar with in VBScript, it would be great (though it would come with its own set of problems). But all Swift does is infer the type of the variable from the first value you assign to it.

This actually introduces problems, because it’s not always possible to unequivocally determine the type of a literal value. So Swift gives you ways to force it to interpret a literal value as a given type. Rather than removing the necessity of the programmer understanding types, Swift thus requires “new and self-taught” programmers to have a mastery of types so that they can understand how Swift is working behind the scenes and make sure that their variables have the desired type.

Strings

Swift is said to improve string-handling over Objective-C (the current language used on OS X and iOS). There is certainly room for improvement there. When I first started programming in Objective-C, one of the first things I did was bring over my own C++ string class, as I found NSString to be overly complicated and muddled. Over the years I’ve gotten better with NSString.

I would argue, however, that some of the so-called “improvements” in Swift with respect to strings are differences without a distinction. So instead of this in Objective-C:

[NSString stringWithFormat:@"The value of num is %d", num]

you say this in Swift:

"The value of num is \(num)"

The Swift version is obviously more concise, but it is also less powerful. To add more complex format specifications to Swift you actually have to invoke the functionality of the underlying NSString class, which means the “new and self-taught” programmer, again, needs to understand the details of the implementation in order to do anything beyond the simplest strings.

One of the stated benefits of string handling in Swift is that “all strings are mutable”. One need not worry about whether the string is declared as an NSString (immutable) or NSMutableString (mutable). Well, you don’t have to worry unless you do have to worry — strings assigned to constants are immutable in Swift. So:

var myString1 = "Mutable string"
let myString2 = "Immutable string"
myString1 += myString2    // perfectly legal
myString2 += myString1    // compile-time error

Switch Statements

Swift eliminates the “fall-through” behavior of switch statements, which is said to eliminate bugs caused by omitting the break at the end of each case block. But, oops, sometimes the fall-through behavior is exactly what you want. So Swift adds the fallthrough keyword. It could be argued that Swift eliminates a line of code (the break) while giving the behavior one normally desires. But at the same time, it adds a keyword (fallthrough) that does the opposite. This requires “new and self-taught” programmers to have the same thorough understanding of switch behavior that Objective-C and C++ programmers do.

Single-line Blocks

The Swift compiler will warn you if you omit the braces in any block (such as after an if) and does not allow single-line blocks, thus avoiding this error:

if (x < 0)
    goto fail;
    goto fail;

The code above will always execute one or the other of the goto statements in Objective-C or C++. Even though the second goto is indented, it is not part of the if-block and will be executed if the condition is false.

Swift will warn you about the missing braces and force you to write this:

if (x < 0)
    {
    goto fail;
    }
goto fail;

Or, for those of you who don’t do your braces the right way, this…

if (x < 0) {
   goto fail;
}
goto fail;

This is fine, and hard to argue with. The supposition is that the programmer will immediately recognize the flaw or won’t make the mistake in the first place. On the other hand, I would argue that the same C++ programmer who wrote the erroneous code will write this in Swift:

if (x < 0) {
    goto fail; }
    goto fail;

I always put braces around my blocks, even if they are one-line, so this doesn’t affect me. It’s ironic, however, that while Swift prides itself in eliminating the unnecessary break statement at the end of a case block, it requires two to four additional lines (braces) in if, for, and while statements, which are more numerous.

PocketBible and Swift

I will be more than happy to learn and use Swift for programming on iOS and OS X. I just don’t believe the hype and won’t convert just for the sake of doing something new.

I am a strong proponent of platform-independent languages like C, C++, Java, and, to a lesser extent, Objective-C (the latter is primarily an Apple language, though it has its origins outside of Apple). Such languages allow me to develop code on one platform and re-use it on another. One of the promises of C++ and Java was that you could develop the code for one platform and use it on many others. Swift is an Apple language (the same way C# is a Microsoft language). It only works on Apple devices. While those are numerous, they’re not the only devices out there. So rather than moving toward the “write once, read everywhere” model promised by Java, we’re back to “write everywhere” as each platform requires its own language.

I don’t mind learning a new language. I already jump from C++ to C# to Java to VBScript to Javascript to MS-SQL on a daily basis. For those of us who write code for a living, being multilingual is a job requirement. This is precisely why I care so very little about the supposed advantages of Swift; this isn’t a religious war for me, it’s just a tool. When someone comes out with a new kind of screwdriver, I may or may not buy it until I need it. And then I’ll just buy one and use it — I won’t try to convert all my screwdriver-toting friends.

So will PocketBible for OS X and/or iOS be re-written in Swift? Probably not today, and probably not until Apple requires it. But Swift depends on Objective-C under the hood, so my guess is that Apple will continue to support Objective-C apps for a long time.

Properties of Uninitialized Session Variables in ASP Classic

From time to time I have to remind myself of the following inscrutable facts, so here they are for posterity:

Given an uninitialized Session variable:

IsEmpty(Session("asdfasdf")) = True
IsNull(Session("asdfasdf")) = False
IsNumeric(Session("asdfasdf")) = True
Session("asdfasdf") = "" in an "if" statement returns True

This indicates that a completely uninitialized value appears to be both an empty string and has a numeric value (presumably zero). This is nonsense, especially given the next example.

Given a Session variable initialized to the empty string “”:

IsEmpty(Session("emptystring")) = False
IsNull(Session("emptystring")) = False
IsNumeric(Session("emptystring")) = False
Session("emptystring") = "" in an "if" statement returns True

In this case, we see that an empty string is not numeric. So to verify that a Session variable does not contain a numeric value, you need to also verify it contains a value at all, since empty Session variables appear to not be empty (i.e. they contain a numeric value of 0).

Enabling Web Inspector in Web-Kit WebViews in OS X Apps

You can turn on Safari’s Web Inspector functionality in any app that uses WebView to display HTML. First, enable the Developer menu in Safari’s preferences. Then enter the following command in Terminal:

defaults write com.example.myApp WebKitDeveloperExtras -bool true

Where com.example.myApp is the bundle identifier for the app. Launch the app, right-click in the WebView, and as long as the developer hasn’t completely disabled the context menu, you’ll be able to select Inspect Element and see the source code running in that view.

A program can enable this functionality itself by executing:

[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"WebKitDeveloperExtras"];
[[NSUserDefaults standardUserDefaults] synchronize];

Similarly, I believe one could defeat this functionality by setting the value to FALSE inside the app.

Symbolicating iOS and OS X Apps

Many of the errors that happen in Mac OS X and iOS apps don’t actually crash the app, they just dump a stack trace to the console. You can view these using the Console app — select the System Log and you’ll see all the messages the app sends to the console.

Unfortunately, these stack dumps can’t be directly used by the programmer to find the bug. With a little work, however, it’s possible to get right down to the line of code that caused the problem.

A stack trace will look like this:

Sep 13 19:04:32 Users-Mac.local PocketBible[727]: *** -[__NSCFString rangeOfString:options:range:locale:]: Range {3040, 18446744073709551600} out of bounds; string length 3504
Sep 13 19:04:32 Users-iMac.local PocketBible[727]: (
		0   CoreFoundation                      0x00007fff910e225c __exceptionPreprocess + 172
		1   libobjc.A.dylib                     0x00007fff96598e75 objc_exception_throw + 43
		2   CoreFoundation                      0x00007fff910e210c +[NSException raise:format:] + 204
		3   Foundation                          0x00007fff94074985 -[NSString rangeOfString:options:range:locale:] + 186
		4   Foundation                          0x00007fff940945b4 -[NSString rangeOfString:options:range:] + 29
		5   PocketBible                         0x00000001077cec78 PocketBible + 797816
		6   PocketBible                         0x000000010776c771 PocketBible + 395121
		7   PocketBible                         0x000000010776aa43 PocketBible + 387651
		8   AppKit                              0x00007fff92c84c38 -[NSTabView selectTabViewItem:] + 389
		9   AppKit                              0x00007fff92ff8b09 -[NSTabView mouseDown:] + 145
		10  AppKit                              0x00007fff92b76a58 -[NSWindow sendEvent:] + 11296
		11  AppKit                              0x00007fff92b155d4 -[NSApplication sendEvent:] + 2021
		12  AppKit                              0x00007fff929659f9 -[NSApplication run] + 646
		13  AppKit                              0x00007fff92950783 NSApplicationMain + 940
		14  PocketBible                         0x000000010770d244 PocketBible + 4676
		15  ???                                 0x0000000000000001 0x0 + 1
	)

The trick, of course, is to find the last bit of PocketBible code that was running when the error occurred. To do this, we need our symbol map. Fortunately, XCode archives that with our program and we can access those archives through the Organizer. So here’s what we need to do:

  1. Create a working folder somewhere
  2. Go into the Archive area of Organizer and select the archived version of the program from which the stack trace was created
  3. Right-click and select Show In Finder
  4. Right-click on the archive and select Show Package Contents
  5. Copy the .dSYM file from the dSYMs folder into the working folder
  6. Copy the application from Products/Applications into the working folder
  7. In Terminal, go to the working folder

Now enter this command:

atos -o PocketBible.app/Contents/MacOS/PocketBible -arch x86_64 -l [load address] [target address]

To calculate [load addresses], subtract the offset you see on any PocketBible line from the address to its left. So looking at line 5, you would subtract 797816 (decimal) from 0x1077cec78 (hex) and get 0x10770c000. [target_address] is the address you see in the stack trace for the line you’re interested in (for example, 0x1077cec78 for line 5).

If you do it right, atos will tell you the object and method, plus the file and line number in the file corresponding to the line in the stack trace:

got symbolicator for PocketBible.app/Contents/MacOS/PocketBible, base address 100000000
-[NSString(HTMLTags) rangeOfHtmlTagInRange:] (in PocketBible) (NSString+HTMLTags.m:67)

Which sends us to NSString+HTMLTags.m, line 67.

If you want to enter several addresses, press enter after [load address]. You are then in “interactive mode” and can enter addresses and get results without leaving atos or re-entering all the other parameters. Press ^C to exit this mode.

Overriding Scrollbar Behavior in OS X

ScrollbarI recently ran into a situation where I wanted to significantly customize the behavior of a scrollbar in a Cocoa WebView and was disappointed in how little access I had to it. There are two factors that complicated my situation. First was the fact that the text I was displaying in the WebView was being loaded dynamically. As the user scrolls up or down, Javascript methods call into my Objective-C code to request additional blocks of text to display either above or below the text already displayed. As the user scrolls up (or down), blocks that are “too far” below (or above) the displayed text are removed by the Javascript on the page. As a result, the built-in WebView scrollbar is displaying completely irrelevant information.

Second, the feature of OS X 10.7+ that allows the user to control whether or not scrollbars are always displayed interfered with my attempts to simply drop an NSScroller on top of the region of the WebView where the scrollbar appears. If the user turned on “overlay scrollbars”, the WebView would re-wrap the text so that it continued under my scrollbar. On top of that, when the system drew its scrollbar, it would draw it on top of mine, even though mine was on top of the WebView in z-order. Furthermore, the WebView would “scroll” the pixels on my scrollbar in the process of scrolling its own text.

It was a mess.

The solution is fairly simple, though:

  1. Drop an NSScroller instance over the right side of the WebView in Interface Builder. The width doesn’t matter as we’ll adjust it in -awakeFromNib to match the width of a standard-sized NSScroller.
  2. In the window’s -awakeFromNib method, enable the NSScrollbar instance, set its size to NSRegularControlSize, and set its initial knob size and position. Also set the WebView‘s scroller style to “legacy”:
    [[[[[webView mainFrame] frameView] documentView] enclosingScrollView] setScrollerStyle:NSScrollerStyleLegacy];
  3. As blocks are loaded and the Javascript reports its position within the displayed text, update the position of the knob.
  4. Connect the NSScroller action to a handler in the code to position the text appropriately with changes to the knob.
  5. Add a handler to intercept distributed notifications:
    [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(observeDistributedNotifications:) name:nil object:nil];
  6. In the handler for the distributed notifications, look for the notification named AppleShowScrollBarsSettingChanged and when it occurs, call a method that forces the WebView scrollbar back to the “legacy” style. You must call this method on a short delay because notifications are not delivered in any particular order. You need to allow the system to change the WebView scroller style before you change it back.

That’s it. The basic idea is to provide your own NSScroller that is updated by position changes in the WebView and which moves the WebView as the user interacts with it. This scrollbar lays on top of the WebView scroller so the user can’t see it. And to keep OS X from inappropriately drawing, we intercept system preference changes that would alter the style of the WebView scroller.

I think this solution would work with any Cocoa view object that is based on NSScrollView. One notable side-effect is that your scrollbar does not auto-hide. In my case, I can live with this.