Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts published in April, 2007

Uli Kusterer, Blake Seely and Andy Finnell have posted follow-ups to Brent Simmons‘ comments on the topic. Worth a read, too.

Uli started his comment with:

Rainer Brockerhoff, the man without version control, has posted…

OK, I guess I should seize the opportunity to confess that in the past I have looked a few times into using Subversion (aka svn) for version control. Xcode currently supports cvs, svn and Perforce. cvs, by all accounts, is old, clunky and obsolescent technology, Perforce is commercial and expensive ($800 per user), so svn is the generally used solution.

Turns out that svn was written by Unix geeks who were unsatisfied with cvs and wanted more capabilities while keeping many cvs concepts and terms. (cvs itself was similarly evolved from the even earlier and clunkier RCS.) Unsurprisingly the whole family tree is exclusively command-line oriented and requires significant neuron grease to adapt to. As I’ve said before, I became sick and tired of command-line stuff in my early career and was extremely glad when, in 1984, I could migrate to the Mac where there was no such thing. Now that Mac OS X is Unix-based I do use the Terminal when there’s no alternative, but in general I try to avoid it. So I had a fast look at svn and its documentation, decided it wasn’t worth the trouble, and went on doing other stuff.

But over the last few days, with the generous help of several people – among them Matt Gemmell, Daniel Jalkut, Tom Harrington, Jeff Johnson and several others on the #macsb channel – I at least figured out enough to be able to set up a repository on DreamHost and tinker around with it. The first byproduct is now online: you can now check out RBSplitView from its own svn repository. Enjoy.

Does this mean that Subversion has now subverted me into doing all my future work under its benevolent dictatorship? No. Xcode 2.4.1 crashes seriously when I try to turn on the version control checkbox, at least for my most-important project. I have deduced that this happens because of some sort of data incompatibility between Xcode and the contents of the dozens of bothersome .svn folders that it insists in maintaining inside of the folders it controls. For simpler projects or older projects it works; for my XRay II project it doesn’t. Bah. For what it’s worth, Leopard’s Xcode 3.0 seems to have fixed this problem and supports many more svn features than the current version; so I’ll probably try this again in a few months (Leopard is still not stable enough to allow me to use it for actual work).

I was going to list a long series of stumbling points and oddball nomenclature that led to my spending several days (instead of hours) on doing these things that should be easy and “just work”, but I don’t think I’ll have the energy for that. Significantly, there’s no complete Subversion GUI client available for the Mac – or for any other platform, I believe. Apparently any hypothetical geek with the necessary masterful understanding of the subversion client and server will by definition also be convinced that a GUI interface will be wimpy and superfluous. (He will probably also believe the same of Xcode.) Also, the server side is seriously lacking in functionality; you can’t do things as simple as wipe a repository or exclude files committed by mistake.

To explain my feelings about svn at this point, I’ll try to reproduce from memory one of Isaac Asimov’s favorite jokes, “Levine the tailor”. I think it’s in his autobiography. You may substitute any other name you find hilarious. (I also wish I’d somehow filmed Háj Ross when he first retold me this joke.)

Morris went to Levine the tailor to have his first suit made. Levine took the necessary measurements and told him to come back in a couple of weeks. Back at the tailor’s shop, Morris tried the suit on and found that it was a little roomy around the shoulderblades. He called attention to that, and Levine replied:

“No problem. Simply hunch your shoulders out a little and look down, and the problem will go away.”

Morris did so, but upon looking down, noticed “Hey, the left arm is crooked!”

“No problem, just hold your left hand like this [demonstrates] and twist your elbow out a little. You see? It’s gone!”

Morris again did so, but then looked further down and said, “And this trouser seam isn’t straight either!”

“Still no problem, just swing your heel on that side out just so and all fits perfectly!”

So Morris pays and leaves the store wearing his new suit, feeling slightly duped by the tailor. An elderly couple watches him lurch by [you should demonstrate this while telling the joke]. The woman says “Isn’t that young Morris? He must have been in some serious accident. He’s all bent and twisted!”

And the man replies: “He must have been, but his tailor is certainly a genius, to make such a perfectly fitting suit!”

Brent Simmons has a long and thoughtful post about his way of doing large Cocoa projects. By all means read the original post and the comments. (Good reactions from Michael Tsai, Daniel Jalkut, Wolf Rentzsch, Blake Seely, I must have missed several others.)

Brent highlights some points: don’t overuse notifications, don’t overuse Key-Value Observing, bindings may be overkill for tables and outlines, C functions for global interfaces, flat source folder organization, learn tricks for fast project navigation. I agree with most. My own largest project is nowhere near’s Brent size of 345 .m files – perhaps also because I don’t mind larger files – but it’s not much simpler than NetNewsWire either. Anyway, bear in mind that my comments below just detail what works for me. YYMV and so forth.

Notifications. Everybody seems to agree they’re not a panacea. I listen to some Cocoa notifications and practically never generate my own. Notifications are great for posting notice of some application-wide event in the hope that some other parts of the application will want to know about it. That’s usually the case when some parts don’t know about other parts, or when one of the parts is a generic framework.

Like Brent, I prefer to use delegates for fast and specific notifications. Say a custom view is resized and someone needs to know when that happens; the logical pattern is to implement a delegate for that view and call it directly. Simple, fast, and easy to trace through. “Easy to trace through” is in fact my main debugging mantra. The bad thing about notifications is they’re difficult to step through in the debugger; you need to place a breakpoint at every listener. The obvious advantage over delegates is that you can have more than one listener – not that I ever needed more than one.

KVO and bindings: I haven’t had occasion yet to use those, although I’ll probably do so for preferences in XRay II. I tried using them in my first plug-in there but backed off fast; they’re certainly not suited to handling nested views that may be loaded and unloaded; the retain cycles get unmanageable. They’re also impossible to properly visualize in the current Interface Builder (though it seems that will change in Leopard?) and even harder than notifications to step through in the debugger. So I’d rather wait for a suitable application to present itself.

I suppose I also should point out that the upcoming Objective-C 2.0 properties look, so far, like another brilliant idea well-suited to specific purposes but not useable elsewhere. The property declaration syntax looks terrible, and the dot notation looks like Java. I can’t see myself using this any time soon – also, notice that the compiler will generate accessor code for them, meaning, you can’t step through.

High-level interface: in my first programs I noticed that I was jamming lots of methods into the application delegate. The app delegate is a singleton, so my other classes were full of lines like [[MyAppDelegate sharedInstance] checkSomethingWith:someStuff]. Later on I changed those to class methods like [MyAppDelegate checkSomethingWith:someStuff], and nowadays they’re just global C functions. I agree they may make it more difficult to refactor the design under certain circumstances, but after a while you learn to look ahead when deciding which functions to use. The only singleton object I have these days is the application delegate.

By the way, I use C functions a lot. Anywhere I see an instance method which doesn’t use “self” or any instance variable, it’s better to convert it into a C function. Same for most class methods. A bonus of C functions is that they’re harder to hack, of course.

Project Navigation: like Brent, I use the function popup a lot. I rarely have so many methods that sorting them into groups with #pragma mark is necessary. I use command-doubleclick and option-doubleclick a lot, and I keep AppKiDo open all the time. I noticed only recently that Xcode has a scripts menu with useful scripts and shortcuts, but the only one I use much is command-/ to comment and uncomment.

By the way, many people rave about using TextMate instead of Xcode for code editing. Apparently nearly all of those people are emacs fans who hate grabbing the mouse and prefer to do everything with memorized key shortcuts. Of course I’m an old fossil who still remembers the WordStar shortcuts and my shortcut neurons seem to be unable to learn new ones; I use the keyboard for cut, copy, paste and save, type short changes with my left hand, and for everything else I resent anything that forces me to take my right hand off the mouse. After all, that’s why we use Macs, right? </slight exaggeration for effect>

But then I suppose most of those people also like compiling their projects in the Terminal… Brent says, “Every time you touch the mouse, God kills a kitten”, but I’d say that for the command key instead icon_smile.gif

Flat folders: Yes, I too have a huge flat folder organization and 1 or 2 levels of grouping in the Xcode project. I never look at most of those files outside of Xcode anyway. I also include my readme and documentation files into the project, and edit them there (I create them in TextEdit however). Some people say this makes reusing code and source repositories harder. I prefer duplicating files or swatches of code when reusing; with some exceptions like RBSplitView, which I include as a subproject.

I seem to be notorious for not using version control systems; currently I keep my source on both my desktop and my laptop, and backup the entire project folder to a new disk image now and then. I very rarely need to refer to older versions anyway – I tend to comment out code instead of deleting it. I may try out Xcode 3’s subversion support, hopefully it won’t make me use the Terminal for anything. Of course, I’ve never worked in a programming team or had to share code with somebody else; blame it on history.

“Haftungsausschluss” means “disclaimer” in German, and Heinz J. Malcharzyk has a quite well-done German translation of an older version of my Ultimate Meta-Disclaimer. He even did some nice additions some of which I immediately retrofitted into my own! Danke, Heinz!

I particulary like the expression “über die Wupper gehen” for “go all higgedly-piggedly [sic]”.

What’s not so funny is that a German court held that websites are by default responsible for the contents of any pages they link to unless they publish an explicit disclaimer to the contrary. Sounds like a very unreasonable default setting to me, but at least I believe I’m well-covered…

Etymology test

No comments

The Presurfer pointed me at The Toughest Word Game on the Web. I got 10 out of 10 on the first try!

Update: Argh. Only 5 correct on the second try, then 8, 5, 8, 9, 8, 10… Warning: a time sink. Though some questions repeat now and then.

Rosyna asked on the carbon-dev list:

But it makes me wonder, is there anyway on Mac OS X to generate a”fast path” from an FSRef? That is, a path that is just the supershort volfs version of the path?

I need to use this myself now and then, so here’s a code snippet that does that:

#import <Carbon/Carbon.h>
#include <sys/mount.h>
const char* shortPath(FSRef* ref) {
   FSCatalogInfo info;
   if (FSGetCatalogInfo(ref,kFSCatInfoVolume|kFSCatInfoNodeID,&info,NULL,NULL,NULL)==noErr) {
      FSRef root;
      if (FSGetVolumeInfo(info.volume,0,NULL,0,NULL,NULL,&root)==noErr) {
         char* path = calloc(1,PATH_MAX+1);
         if (FSRefMakePath(&root,(UInt8*)path,PATH_MAX)==noErr) {
            struct statfs fs;
            if (!statfs(path,&fs)&&(fs.f_flags&MNT_DOVOLFS)) {
               snprintf(path,PATH_MAX,"/.vol/%lu/%lu",fs.f_fsid.val[0],info.nodeID);
               return path;
            }
         }
         if (FSRefMakePath(ref,(UInt8*)path,PATH_MAX)==noErr) {
            return path;
         }
         free(path);
      }
   }
   return NULL;
}

To use it, pass in your FSRef and you’ll get one of these back:

  • A short volfs path, if the volume supports volfs, or
  • A normal path if the volume doesn’t support volfs and the path is shorter than PATH_MAX, or
  • NULL.

If the return value is not NULL you’re responsible for freeing the path buffer after you’re done with it.

There are some issues with volfs paths you need to be aware of. The canonical reference here is Technical Q&A QA1113: The “/.vol” directory and “volfs”, which says:

WARNING:

Under no circumstances should your application construct paths within “/.vol”. This area of the file system is reserved strictly for the Carbon File Manager. The structure of the “volfs” file system is likely to change in a future releases of Mac OS X. You must use the following description of the “volfs” path structure for debugging and performance analysis only.

If you pass the path generated by my code snippet to any BSD routine it should work. You should however treat the path as opaque and not rely on its contents. About the only thing that also works is, if your FSRef points at a directory, you can concatenate the UTF8 name of a contained file (preceded by a slash) onto that path – you can’t add more than one though.

The snippet relies on one non-documented feature of the statfs call, namely, that the volfs volumeID is returned in the f_fsid.val[0] field. Needless to say this can break anytime in the future, and you may not want to rely on this for shipping applications. That said, it would certainly be useful to have the File Manager return a guaranteed short opaque path that could be passed to BSD calls. I plan to file a bug requesting this.

As QA1113 says, this could break in any future version of Mac OS X – I’m sure it works from 10.1.5 up to 10.4.9 though. You might want to insert a stat() call before returning the volfs path, if you’re really concerned about that… this is left as an exercise for the student.

Regarding the new Leopard shipping date, Rosyna says October is still spring – spring in the southern hemisphere, that is. As I’ve said before, Apple should think more globally and if that’s the first evidence for it, I approve… icon_smile.gif

Update: best summary of the situation from Wil Shipley.

Leopard is delayed for 4 months – until October. John Gruber has a good analysis, as does Daniel Jalkut.

A couple of weeks ago I wrote:
Rainer Brockerhoff wrote:

Even so, people who have not seen anything of Leopard beyond some leaked screenshots wrote excitedly about a MacWorld release, then about a March release, then when their wild predictions aren’t confirmed start to moan that “Apple’s been having trouble getting Leopard out” and now, even, that “Leopard had reportedly been delayed until October”. I really hope that Apple will show more details before WWDC, but I won’t be too surprised if they don’t.

The reference was to this DigiTimes story, which I didn’t even want to link to at the time because it sounded so absurd. Well, looks like they got it right, although the excuse for the delay is the iPhone, not Boot Camp. Although this is not stopping some people arguing that one of things apple will do during the extra months is converting Boot Camp into a Parallels-style virtualizer – something I’d previously described as likely to be implemented in firmware, until they took the TPM out of newer Intel Macs.

In retrospect, it’s not too surprising. Unusually, Apple is releasing 3 major products this year – TV, iPhone and Leopard – and all run some form of OS X despite having very different target markets and form factors. (Also unusually for Apple, all 3 were pre-announced.) So far, only the iPhone hasn’t been delayed, and clearly Apple felt that delaying all 3 would be a serious PR loss. Ergo, putting people to work on the iPhone makes some sense, supposing Apple managed to avoid the mythical man-month effect.

It’s still difficult to assess what this means for the upcoming WWDC. Sure, a feature-complete build will be available there, but unless something revolutionary new thing is revealed, it may not have much impact. Launching the iPhone there won’t be a big thing for developers unless a SDK is announced. I won’t be able to go this, so it seems I won’t miss much…

Folks on the #macsb IRC channel were talking about testing if an application was being run from a disk image, and it occurred to me that some code from XRay (already being adapted into XRay II) would be suitable for that. They suggested making a category on NSWorkspace, so here it is.

So the sample app project has a category on NSWorkspace which takes a path argument and returns a NSDictionary with some details about the volume and device. The app shows the attributes for its own path first, then you can check any others. Easy to test if the path points into a disk image or network drive, too. Please read the “ReadMe” file for details and caveats.

Suggestions are welcome. Please test this on your system and on any weird disk images, external drives or network volumes, and send me the results if they don’t look OK.

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2017 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.