Borkware Miniblog

October 29, 2007

Speed Download for Apple Seeds

Filed under: irc, Random — Mark Dalrymple @ 10:25 am

Apple provides downloads for OS X version for developers with seed keys. That’s cool.

Apple’s webservers cut off long downloads after twelve hours. When it takes twelve hours and fourteen minutes to download something, that’s not cool. I don’t want to think how many multigigabytes I downloaded before figuring out that twelve-hour cutoff.

Jonathan Wight said on IRC one day, “dude, use Speed Download“. I did. It works. I watched the progress meter at 12 hours. download speed went to zero as expected. A couple of seconds later it cranked back up Fourteen minutes later I had a finished download. That’s cool.

October 26, 2007

ZeroLink, Rest in Pieces

Filed under: irc, programming — Mark Dalrymple @ 11:28 pm

6FF1A549-451F-4BCB-9EB5-3317786D19E3.jpg

One thing that made me happy, and was greeted with applause at WWDC, was the news that ZeroLink is gone in Leopard. The linker is now fast enough to make ZeroLink unnecessary.

So what was so bad about ZeroLink? The first problem wasn’t actually ZeroLink’s fault – it was Apple making ZeroLink on by default for new Xcode projects. A common refrain heard from new Mac programmers was “I made a Cool Little Cocoa App, sent it to a friend it won’t work for him. What’s wrong?” ZeroLink.

ZeroLink performed its magic by demand-loading object files, and those object files weren’t included in the application bundle until several Xcode revisions later. So sending an App to a friend (or a reviewer, or a cow-orker) would mean sending them a broken app. Then the programmer would ask for help on a mailing list or IRC, get told to turn of ZeroLink, and then rebuild and re-send. In fact, the Feenode #macdev FAQ has a special section just for ZeroLink.

This was embarrassing and demoralizing, especially for someone new to the platform. New, small projects didn’t benefit from ZeroLink anyway, and you have to have a pretty large program before the time savings is noticeable. Someone with a project that big will have someone intimate with Xcode who would know about ZeroLink, so need to have it on by default.

The second problem was that ZeroLink introduced instability, with its frequent refrain being “I’m getting weird crashes”, which are fixed after turning off zero link. I got paid for a full day’s consulting tracking down a strange C++ operator new overload. The daily smoke test built and ran great, but development versions crashed and burned in weird places. We finally tracked the main difference between the developer builds and the automated builds: ZeroLink. Turned it off, rebuilt, and life was happy ever after. This particular app (which was freaking huge) was broken down into lots of frameworks, so link time wasn’t that much longer than with ZeroLink. (Because of this framework breakdown, I was able to pull some command-line tricks to prevent unnecessary recompilation of other parts of the system, and greatly reduced my turnaround time on a TiBook500 vs the G5-weilding full-timers, but that’s a story for another day.)

Good bye ZeroLink.

September 13, 2007

C Callbacks in ObjC

Filed under: amosxp, irc, programming — Mark Dalrymple @ 11:23 am

It’s interesting to see common subjects come up in the IRC channels. When someone unfamiliar joins and asks the question “how do I put a method into a function pointer?”, 9 times out of 10 they’re actually wanting to use Cocoa with an existing C API that uses callbacks. A much better question would be “I’m using a C API that uses callbacks with Cocoa, how do I make it work?”

The Answer

You can’t use Objective-C methods as callbacks. Stop trying, you’ll just make yourself angrier. You have to bounce off of a regular C function, and use any “userData” or “info” mechanism in your C API to pass a pointer to your object.

So assuming you have a call SetDrawingCallback, which takes a function, but you actually want to draw using your objecty-goodness OblateSphereoid object, you would do something like this:

BWOblateSphereoid *egg = [[BWOblateSphereoid alloc] init];
 
SetDrawingCallback (drawingContext, /* context that wants to draw */
                    drawEggThunk, /* the function that the context will call */
                    egg);  /* arbitrary userData pointer */

Then in your callback function:

void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData)
{
    BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData;
    [dealie drawAnEggInRect: areaToDraw];
} // drawEggThunk

You are allowed to call Objective-C methods in a C function. You just need to make sure your file is compiled as Objective-C, whether you have a .m extension, or tell Xcode to compile it as Objective-C explicitly. If your callback API doesn’t let you pass in a userData pointer (a rock to hide your data under), you’ll have to put your object into some global location for your C function to find.

If you need to poke inside of the object directly, you can put this function inside of the @implementation block of your class, and then you can access instance variables with the C arrow operator. But that’s kind of naughty, so to preserve your Purity of Essence you should be using method calls on your object. End of Sermon. Here’s the evil:

@implementation OblateSphereoid
 
void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData)
{
    BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData;
    dealie->_frognatz = [NSColor plaidColor];
    // and more stuff.
} // drawEggThunk

...
@end // OblateSphereoid

Why?

So why can’t you just (somehow) get the address of -drawAnEggInRect: for the BWOblateSphereoid class and pass that for the drawing callback? The answer is a secret. Two of them, in fact.

When you use brackets in Objective-C to send a message to an object, the compiler is actually generating a call to the C function objc_msgSend (or to one of its variants, but let’s keep it simple):

id objc_msgSend(id self, SEL op, ...);

So something like [egg drawAnEggInRect: someRect] turns into:

objc_msgSend (egg, @selector(drawAnEggInRect:), someRect);

Which then calls drawAnEggInRect:, which under the covers boils down to something like this:

void drawAnEggInRect(id self, SEL selector, Rect someRect) ...

self and the selector are passed in as secret hidden parameters, and then any arguments for the method follow them. This is why you can’t just use the address for a method’s code in a C callback API. The library code invoking the callback will be wanting to put its own stuff in the first couple of arguments, which will cause all sorts of nifty explosions when Objective-C starts interpreting those as object pointers and selectors.

September 6, 2007

It’s Still Just C – arrays and pointers

Filed under: irc, programming — Mark Dalrymple @ 8:35 pm

Another fine day on IRC. An individual was stating that you couldn’t pass C arrays to Objective-C methods. That surprised me, so I wrote a little little command line program to check (the program is at lisppaste.) Of course, it turns out you can – Objective-C is still just C. And because it’s just C, you have the behavior of arrays and pointers being pretty much interchangeable.

For instance, you can pass a C array to a method:

- (void) ookie: (int *) snork {
    NSLog (@"%d %d %d", snork[0], snork[1], snork[2]);
} // ookie

Or use the [] syntax:

- (void) ookie2: (int[]) snork;

or use the explicit size syntax (which doesn’t really matter for 1-D arrays):

- (void) ookie3: (int[17]) snork;

And you can pass in pointers to pointers to pass back a resized array originally allocated by malloc:

- (void) ookie4: (int**) snork
         growTo: (int) elements {
 
    *snork = realloc(*snork, sizeof(int) * elements);
    (*snork)[0] = 55;
 
    NSLog (@"(%d) %d %d %d", sizeof(snork), (*snork)[0], (*snork)[1], (*snork)[2]);
 
} // ookie4

Passing in arrays of Objective-C types isn’t a problem either:

- (void) ookie: (NSString **) snork {
    NSLog (@"%@ %@", snork[0], snork[1]);
} // ookie

Just make sure your syntax is declaring the original array is good:

NSString *blargh[] = { @"oop", @"ack" };

(the original poster had confusion about Objective-C objects needing to be pointers, having a declaration of NSColor blargh[] = { ... }; and then stating that things aren’t possible)

It does go without saying that you should prefer NSArray, or another collection class, to naked C arrays. Sometimes you need to use the lower-level mechanisms, so the power (and pain) is there if needed.

August 25, 2007

In praise of little command-line apps

Filed under: irc, programming — Mark Dalrymple @ 1:54 pm

Folks who have hung around with me know I’m an emacs weenie. It’s not that its necessarily the best tool in the known universe, but it’s what I’ve been using for 17+ years as a paid professional on a number of different platforms, and I’ve developed a number of workflow habits that give me the illusion of being productive.

Central to my daily workflow is having several shell buffers open in my emacs session. This means I can boing from a source file to a shell with a half dozen keystrokes.
One side effect of this is that I can create, use, then forget about little command-line programs extremely quickly. They become great little testbeds. No need to create an Xcode project, or create an Executable in an existing Xcode project. I understand that BBedit and Textmate let you run shells within the editor without any extra baggage, which is all kinds of awesome.

One day on the #macdev IRC channel, someone was complaining (gee, that never happen!) that they tried to NSLog a dictionary, and It Didn’t Work. Someone else, who is ordinarily always correct, suggested that NSLog might send -description to the first argument. I didn’t think so, but wasn’t sure enough to argue. So I hopped over to Terminal, made a little program, and tried it out. Turns out you get a compiler warning if you pass a non-NSString to NSLog, and then the program gets an exception when NSLog tries to send -length to the passed-in object.

Knowledge gained in under a minute.

And now I’ve burned an hour writing about it. Oh well. But I’m waiting on a flight, so it’s time better spent than reading yet another Lord Peter Wimsey novel.

Here’s the program:

#import <Foundation/Foundation.h>
 
/*
gcc -g -Wall -framework Foundation -o logger logger.m
*/
 
int main (void) {
    [[NSAutoreleasePool alloc] init];
    NSDictionary *arg = [NSDictionary dictionary];
 
    NSLog(arg);
 
    return (0);
 
} // main

And it took about a minute from initial question to the acquisition of knowledge, including fixing a syntax error. More sophisticated test programs may take longer, but usually not that much longer.

I do this kind of stuff when playing with a new Cocoa class, too. It’s much easier to cook up a little ad-hoc test case to verify my understanding of some aspect of NSWhatever than to try to scaffold something in a big application.

OK, so what are the important highlights of the code? The first interesting bit is the compile line I’ve got in the comment. Having a compile line in each source file makes it easy to find the file, copy out the compile line, paste it into a terminal and go. No need to modify a project or a central makefile (although those studlier than I with makefiles could make an implicit rule for *.m files, but I’ve already have enough scar tissue on my soul courtesy of make) This also makes it handy for folks who are looking at the code after you put it into a pastebin. No need for them to figure out how to run it. Just save the text, copy the command and then paste it into Terminal.

For folks not familiar with the gcc command, here are the moving parts:

  • gcc : run the C compiler. If you’re doing C++, use g++
  • -g : turn on debugging. You might need to run your program in the debugger.
  • -Wall : turn on a bunch of warnings. If your code has any warnings, don’t ask anyone for help until you fix those warnings. To do otherwise would be rude. Although it’s ok to ask for help if you’re having trouble figuring out what a warning means.
  • -framework Foundation : use the Foundation framework. This lets #import <Foundation/Foundation.h> work, and also satisfy the linker when you use Foundation functions and classes. If you’re using AppKit too, then use #import <Cocoa/Cocoa.h> in the code and -framework Cocoa on the command line.
  • -o logger : create an executable program called logger. If you omit this, the incredibly obvious name of a.out is picked by the compiler.
  • logger.m : the source file to compile.

After that comes the main() function. You don’t need to declare argc and argv if you’re not interested in the command line arguments. After that I usually make an autorelease pool, and then the stuff I want to test. main requries a return, so you gotta add one, or else the compiler will whine at you.

You may have noticed I didn’t use a template file with all this boilerplate stuff already filled out. It’s just a personal weirdism I guess. It takes me longer to find the file, edit the parts that change (whether to use Foundation, Cocoa, or neither; the file name; any additional complier flags like -D), and navigate around than it does to just blort out everything linearly. But I’m a very fast typer and don’t like to wait for personal pipeline stalls when having to make decisions.

Many of the examples in AMOSXP are like this — small stand-alone programs that explore one thing. I’m not sure which came first, doing all of the examples, or using small apps to test something I need to figure out. But no matter where it cam from, I’m a big fan of the technique.

August 19, 2007

Objective-C is Stupid (but I still like it)

Filed under: irc, programming — Mark Dalrymple @ 6:47 pm

One of my guilty pleasures is hanging out on Mac programming IRC channels (#macsb and #macdev on irc.freenode.net) Occasionally an interesting discussion erupts over some esoteric topic, but for the most part it’s ordinary questions about the basics of Cocoa programming.

One misconception about Objective-C that comes up occasionally is the assumption that Objective-C does more than it does. In particular things like


“I compare two strings/objects/dictionaries with ==, and the test fails. Cocoa is broken!”
(quickly followed by the Mac sucks, Xcode blows goats, and so on)

or


“Can I concatenate two strings by using + ?”
(quickly followed by the Mac sucks, Xcode blows goats, ObjC2 should have gotten operator overloading, and so on)

Objective-C is a pretty old language, predating Java, Perl, Pythong, Ruby, and many of the modern features of C++. It is just C with a couple of extra knobs on it, with very little extra behavior added to the language. All of the magic is in the runtime which does message dispatching. There is no operator overloading in the language. Pretty much all the language lets you do is interact with integer and floating point values, and calculate addresses via pointers and offsets. In C and Objective-C, there is no implicit complex behavior hiding behind the operators.

Now, folks who come from VB (I presume), Java, scripting languages, and C++ expect things like the == operator to be an equality operator, knowing the contents of the objects being compared; or expect the + operator to be a concatenating operator, dynamically creating objects.

Think about what happens under the hood: comparing two strings compares each of the characters in the string (looping over the contents), or comparing two dictionaries would compare each of the elements in the dictionary (looping over the keys). Likewise, to concatenate two strings, you’ll probably be looping over the two, or allocating blocks and using a memcpy()-like operation. (and in general, using concatenation to build strings can bite you when you go to internationalize your application)

C and Objective-C don’t do anything that convenient. All == does is compare a small number of bytes for an address when dealing with pointers or an integer/float value. And when you come down to it, those are the same operation. In particular, no looping. All + does is add two values. In particular, no allocations.

So, when you’re dealing with Objective-C, and things don’t behave the way you think they should, consider what’s going on under the hood:

NSString *thing1 = ...;
NSString *thing2 = ...;
 
if (thing1 == thing2) {

This is just pure C right here (no @‘s or []‘s are involved, so the Objective-C part of the world doesn’t kick in. No ()‘s involved, so no function calls are happening. Therefore, only a small number of bytes are involved. Each string could be megabytes long, but the comparison will just be four bytes (eight bytes on a 64-bit system). So this is just testing whether one address is equal to another address. An “identity test”, vs a test for equivalency, which is what the programmer probably wanted in the first place. Assuming that the two strings are not pointing to the same @"literal NSString", these will have different addresses, and the comparison will be a false one. (it’s not my nose, it’s a false one)

Now this code:

if ([thing1 isEqualToString: thing2]) {

Does do an equivalency test. Since you’re actually invoking a method here, and methods are arbitrary code, this has the opportunity to loop through the strings and compare them character by character.

So the moral of this poorly-organized story? C is dumb about data. It only does a few blindingly simple things. Objective-C is a very thin layer on top of C, and adds nothing to the existing C syntax. If you’re getting unexpected results with the built-in operators, you’re probably assuming the base language is doing more than it should, and you should update your expectations appropriately.

And while I’m thinking about it, I’m quite glad Objective-C does not have operator overloading. The gotchas are just too subtle, and I don’t mind trading some extra typing or an explicit function or method call in exchange for not having to track down subtle changes in behavior when some class I’m using decides to overload an operator. Hint: in C++, how does operator&& change behavior when it’s overridden, vs the compiler default? You’d be surprised how many experienced C++ developers don’t know that bit of trivia.

If you really want operator overloading (it does make sense in some situations, like the canonical matrix libraries everyone seems to be writing, or at least using for examples of why overloading is a Good Thing), there’s always Objective-C++.

Create a free website or blog at WordPress.com.