sayHello
| result |
result := «printf(('Hello, world!' asCString):Ptr):Int».
[result < 0] ifTrue: [ Exception raise: 'Error calling printf.' ].
^self
This is a method, sayHello, that invokes the ExternalMethod listed in the module-global ExternalMethodDictionary under the key symbol #printf. It declares the argument and return value types and uses some of the object coercions built into the SmalltalkAgents frameworks to get values that will be passed to the foreign code properly.You've all read about the Road to Lisp. I was on it for a little over a year. It's a great road, very enlightening, blah blah blah, but what they fail to mention is that Lisp isn't the at the end of it. Lisp is just the last semi-civilized outpost you hit before it turns into a dirt road, one that leads into the godawful swamp most of us spend our programming careers slugging around in. I guarantee you there isn't one single Lisp programmer out there who uses exclusively Lisp. Instead we spend our time hacking around its inadequacies, often in other languages.Steve does a very good job of articulating a lot of the things I dislike about Lisp, especially Common Lisp. One interesting thing, though, is that a lot (but not all) of the issues he raises are addressed by Dylan.
Therein lies the debate. Years of whinging by lazy CS undergrads like me, combined with complaints from industry about how few CS majors are graduating from American universities, have taken a toll, and in the last decade a large number of otherwise perfectly good schools have gone 100% Java. It's hip, the recruiters who use "grep" to evaluate resumes seem to like it, and, best of all, there's nothing hard enough about Java to really weed out the programmers without the part of the brain that does pointers or recursion, so the drop-out rates are lower, and the computer science departments have more students, and bigger budgets, and all is well.Of course, those recruiters don't actually use grep. They have some "fancy" Access database that a "consultant" wrote for them that looks for keywords in Word documents.
I just figured I would take some time out for a public-service announcement.
If you're developing Mac OS X software, you should really be on the appropriate developer mailing lists. Apple hosts a number of mailing lists at lists.apple.com and hosts archives there too. The lists are managed with GNU Mailman and have its convenient subscription and administration interface.
In my opinion, the principal lists for application developers are:
| carbon-dev | Developing software with the Carbon framework. |
| cocoa-dev | Developing software with the Cocoa framework. |
| java-dev | Developing software for Mac OS X in Java. |
| webobjects-dev | Developing web applications with WebObjects and EOF. |
| xcode-users | Using the Xcode Tools suite for Mac OS X development. |
There are also a whole lot of task- and technology-specific lists, including lists for developers implementing AppleScript support in applications, developers working with networking, developers creating device drivers, developers writing multithreaded applications, developers working with Xgrid...
Be sure to look through the list of lists to see what else you can take part in.
<gsmarkup>
<objects>
<window title="This is a test window" closable="no">
<button title="Print Hello!" action="printHello:" target="#NSOwner" />
</window>
</objects>
</gsmarkup>This gsmarkup file specifies an NSWindow with no close box and the title "This is a test window", which contains an NSButton titled "Print Hello!" that sends -printHello: to the object that owns gsmarkup (set when the gsmarkup is loaded). Note that you don't have to specify the size of the button, where in the window it is, etc. You can if you want (or need) to, you just don't have to. And if you don't specify a target for a control, its target is assumed to be nil (the First Responder).id attributes in a markup to name objects and then refer to them using the standard reference (#foo) notation to wire them together within the same gsmarkup file.setjmp and longjmp for exception handling, and neither the language nor the framework had built-in thread synchronization primitives. (Cocoa did have several classes providing synchronization functionality though.) NS_DURING
{
...
[NSException raise:NSInvalidArgumentException
format:@"Invalid argument '%@' to method 'blah'", argument];
...
}
NS_HANDLER
{
if ([[localException name] isEqualToString:NSInvalidArgumentException]) {
// handle the exception
} else {
[localException raise]; // re-raise the exception
}
}
NS_ENDHANDLER @try {
...
@throw [[[MyInvalidArgumentException alloc] init] autorelease];
...
}
@catch (MyInvalidArgumentException *invalidArgumentException) {
// handle the exception
@throw; // re-throw the exception if it wasn't handled
}
@catch (id allOtherExceptions) {
// all other exceptions will be caught by this general construct,
// or if it isn't used, they'll be caught higher up the call chain
// just like in Java or C++
}
@finally {
// do any cleanup that needs to be done regardless of whether
// an exception was thrown
}synchronized keyword; the only thing supported are blocks synchronized on a single object. But that's plenty because it means you no longer have to maintain your own NSLock for simple synchronization: NSMutableArray *sharedQueue = [[NSMutableArray alloc] initWithCapacity:5];
...
@synchronized (sharedQueue) {
// add an element to the shared queue
[sharedQueue addObject:object];
}
...
@synchronized (sharedQueue) {
// remove an element from the shared queue
if ([sharedQueue count] > 0) {
element = [sharedQueue removeObjectAtIndex:0];
}
}See? Much more straightforward than managing a separate NSLock. (Of course, for shared work queues you're generally better off using an NSConditionLock but this is just an illustration...)/var to actually update all of the packages installed as part of the operating system with up2date! How stupid is that? So I wiped and reinstalled, and had to fight the interface to the stupid disk partitioning tool in order to get it set up how I wanted it. How did I want it set up? On drive 1, I wanted the usual 48MB (or whatever) /boot partition, followed by swap space, followed by a single huge / partition. And that's only because it complained at me about not having a separate /boot partition; I would have rather had just a single partition per disk. Drive 2 is a single partition that's going to serve as backup for the time being./sbin/chkconfig --add httpd to add httpd (not apache as one might think) to the startup process. But wait! That didn't add it to the startup process! What did it do? Evidently, it just made it visible to the startup process. To actually add it to the startup process, I had to use /usr/bin/ntsysv -- whatever the hell that stands for -- to go through a little list and put a check next to httpd. Then, finally, it would run at startup.up2date and because I can't imagine how much my life would suck if I tried to make my own version of Apache interact with the Red Hat startup system. I also installed the Java2 version 1.3.1 (update 04) SDK instead of 1.4, because WebObjects is really only qualified against 1.3.1 right now. (Maybe when WebObjects 5.2 ships it'll be qualified against 1.4, and I can upgrade.) I also had to adjust the instructions to refer to the proper paths:/etc/httpd/confapxs is at /usr/sbin/apxs/usr/include/apachecgi-bin is at /var/www/cgi-bin/var/www/html(entity = 'MyEntity') => propertyKeys = "(name, creator)"
((task = list) and (entity = 'MyEntity')) => propertyKeys = "(name)"