I apologize if this entry is incoherent or trivial. But I need to build up the habit of blogging.
I recently picked up a copy of Refactoring. I hadn’t heard of that book before I read Steve Yegge’s thoughts on it – indeed, my entire concept of refactoring had previously been limited to Eclipse’s built-in tools. To describe this book as an eye-opener would be an understatement; not only has it taught me many coding strategies (upon reading the entry for Introduce Null Object, I practically screamed “Why didn’t I think of that?”), but it’s also changed many of my ideas about the way I code.
Fowler’s clear, direct writing is one of the strengths of Refactoring; during the book, he introduces the concept of the code smell – a term which I had not heard before, and which perfectly describes a situation with which I have been familiar ever since I started coding – and points out that a sure-fire sign of smelly code is the presence of many comments; if you need to explain a method in excruciating detail, then you’re probably made it too complex.
One of the reasons why I adore Eclipse for Java development is because it shows JavaDoc attributes in its Intellisense methods – I don’t need to navigate through the Java API when I can hit Ctrl+Space and see the arguments the method takes. Without Eclipse, I have to either rely on memory (and in my opinion, life’s too short to memorize the proper sequence of arguments that a proper BufferedReader instance takes) or waste time navigating the API docs.
Objective-C, on the other hand, doesn’t have this – because method signatures can be broken up into multiple pieces. Take a look at these two method signatures – taken straight from the documentation:
- (NSRange)rangeOfString:(NSString *)subString options:(unsigned)mask range:(NSRange)aRange
public NSRange rangeOfString(String s, int i, NSRange nsrange)
When looking at the first method signature, I know that the second object will be an integer that controls the masking – simply by virtue of the fact that, like its parent Smalltalk, its methods recieve messages via keyword messaging. I can also make the assumption – and it is only an assumption – that
- (NSRange)rangeOfString:(NSString *)subString options:(unsigned)mask and
- (NSRange)rangeOfString:(NSString *)subString are valid methods. With the Java API, on the other hand, I have no clue what the second argument does; if I had to know, I’d need to be using Eclipse or XCode, not Emacs or Textmate. Textmate’s Cocoa completions don’t show any HeaderDoc information – but that doesn’t matter: the keywords tell me what the arguments are used for.
It seems to me that Objective-C’s syntax lends itself to clarity by its very nature; Java, on the other hand, depends on other programmers being clear and helpful in their method signatures. And as a short perusal through The Daily WTF reveals, programmers can be very, very unhelpful at times.
+ (NSString *)humanReadableFileType:(NSString *)path
NSString *kind = nil;
NSURL *url = [NSURL fileURLWithPath:[path stringByExpandingTildeInPath]];
LSCopyKindStringForURL((CFURLRef)url, (CFStringRef *)&kind);
return kind ? [kind autorelease] : @""; // If kind happens to be an empty string, don't autorelease it
Thanks very much to Peter Hosey and David Phillip Oster for being unbelievably helpful in clearing up the labyrinth that is CSStringRef to NSString usage.
Any rational programmer will agree that different situations need different solutions. If you’re trying to write a blazing-fast and lightweight *nix process monitor, you wouldn’t use something like Ruby instead of C – Ruby’s just too slow. If you’re trying to write a tool which almost any programmer can easily read and modify, you wouldn’t use Haskell instead of Java – Haskell’s just too different. Up until now, I hadn’t even thought about the ‘right-tool-right-job’ tenet of my programming beliefs – but yesterday I did, and I came to a frightening conclusion.
Information technology is the fastest-changing industry in the world. New problems and solutions shift faster than you can blink; it’s almost every day I hear something about Nice or Groovy or some other language about which I know nothing. With such a massive shift of problems, solutions, and tools, it’s inevitable that some of them are going to be isolated.
Take XMLHttpRequest. (Please. *badum-shish*) Until Ajax came out, it was a solution in search of a problem; it’s pretty astounding to think that it took 6 years (XHR was developed by Microsoft in 2000) for such a brilliant solution to find a problem to solve. (The question of whether XHR is solving that problem, or if that problem actually exists, is another matter entirely.)
Now take Perl. Back in the early days of the web, it was indispensable – CGI was crucial for everything – and there was almost no other tool that could solve such a huge problem as how to glue together all the components that make up the Web. But now PHP, Python and Ruby have muscled in on the domain that Perl used to rule unchallenged; it seems as though this tool has lost its problem. If I were to develop a new, radical application Perl would be the last thing I’d choose – it’s old, not particularly fast, impossible to maintain, and Perl 6 is still far, far off.
What I’m saying is that if there’s one thing which your pet language does really well, then diversify. If, like Perl, you rest on your laurels, the problem you fix might be fixed by someone else. Sure, you should always pick the right tool for the right job – but if you’ve got a great tool which solves no problems, you’re never going to get anywhere.
I came to this conclusion after looking at REALBasic. Though I loathe everything that Basic and its progeny stand for (I have justification for this; I once had to write a 60-page tutorial on Microsoft Access & VB), I have to admit its crossplatform nature, especially for OS X widgets, is nearly flawless. After looking at the page, I mused on how much better Cocoa is than VB – and then it hit me like a lightning bolt:
What if REALBasic published something that could emulate the iLife window look?
How would new Mac programmers feel if they had to choose between a harder language /API that only works on Macs (yes, I know about GnuStep) and an easier language that works crossplatform and allows one to make slicker-looking applications than the other choice?
Yeah, there are fantastic third-party libraries that do the iLife thing for Cocoa, but what if REALBasic had it as part of the standard package?
Unless Apple gets their act together soon, their niche of native-looking, great application design might be invaded by REALBasic. Don’t let Cocoa fall into the trap of ‘good tool, no job’.
Here’s what I realized: it seems that every language under the sun is being evangelized as an excellent functional programming language simply because it supports a few paradigms from FP.
Or, restated: Anonymous functions do not a functional language make.
The most egregious example of a pundit claiming a language is functional when it’s clearly not is Eric Kidd’s well-known Why Ruby is an acceptable Lisp. Kidd tells us explicitly that Ruby is a denser functional language than Lisp – and I’ll be the first one to admit that if I were to debate the “denser” part of that sentence, I wouldn’t know what I was talking about.
But Ruby is not functional – Wikipedia calls it a reflective, object-oriented programming language, and I agree with them. Yes, you can have block arguments to methods, continuations, generators, reflection, and metaprogramming – but it isn’t functional, for two reasons.
1. It’s hard to carry around functions as objects.
I really don’t know why Ruby hates parentheses so much – it’s probably part of its Perl heritage. In Ruby, you can call methods without sticking superfluous parentheses in there – take a look at this Python code:
" I'll write about Cocoa soon; disaster struck the app I was writing ".strip().lower().split()
Now take a look at the equivalent Ruby code:
" Apple's releasing a tool
with XCode 3
which completely supersedes my Cocoa app - so I'm very depressed right now ".strip.downcase.split
Though you could put parentheses in front of
split, Ruby will work just fine without them. Now, this feature makes for far fewer parentheses, thereby making code significantly more readable. But what if I want a previously-declared function as an argument? If I type in the name, Ruby will just evaluate the function. Sure, I could use the kludge that is Symbol.to_proc, but that’s ugly – and it wraps the function inside a Proc object, which has to be called with the
call(*args) method. And that’s just ugly. In Python, all you need to do is type the function’s name to use it as an object, and append a pair of parentheses if you need to call it.
2. Variables are.
A purely functional language only has immutable variables. Ruby doesn’t. (Yes, I know LISP isn’t purely functional. But it adheres to so many other FP paradigms that we can overlook that.)
But I’m getting distracted, so I’ll cut the above point short.
Anyway, what I wanted to say was this – just because your pet language has support for anonymous functions/closures doesn’t make it a functional language. Sure, Python has
In conclusion, don’t say your language is a functional one just because you borrowed a few ideas from Lisp. If you want a real functional language, try OCaml, Haskell, ML, or Scheme. Calling imperative/OOP languages functional just makes the term meaningless.
(Note: I really, really like Ruby and Rails. Anything disparaging that I say about either of them should be taken with several grains of salt. If I seem to be encouraging Pythoneers to crush Rails, it’s simply because I love both, and want all frameworks to be constantly innovating.)
Everybody with the slightest interest in web development has heard of Ruby on Rails. It thrust Ruby into the spotlight, created a hype machine that stubbornly refuses to go away, and made David Heinemeier Hansson a celebrity. I adore Rails – it’s by far the best web framework for simple CRUD apps. However, as a Python devotee, it hurt me deeply to see Ruby stealing the spotlight. As such, I embarked on a quest to find out why Rails is winning; I looked at Django, Turbogears, Pylons and web.py. After months of building the same simple CRUD app, I came to the following conclusion:
Python can beat Rails. It can grind it into a pulp in every way concievable – speed, elegance, coolness, extensiblity, organization, AJAXness, beauty, and flexibility. It can send Rails crying home to David while Guido basks in the Web 2.0 spotlight. But right now, Rails is thoroughly torching all of the Python web frameworks. The following is a list of recommendations that, if applied to a Python framework, could dislodge Rails from the position of King of the Web Frameworks.
As many of you know, Apple is releasing the new incarnation of Objective-C (creatively dubbed Objective-C 2.0) along with XCode 3.0 and Leopard. Though much of it is hidden under Apple’s elaborate nondisclosure agreements, people like Andy Matushack and Scott Stevenson as well as other sites have uncovered more information from the ObjC mailing lists and repositories than the meager scraps of info that Apple released on their website.
Since I can’t give any new information about this, I’ll just list my opinions, then brace for the reaming I’ll receive in the comments.
Disclaimer: Apple may change all of these things. This post is naught but conjecture heaped upon conjecture.
(Update: as usual, Scott Stevenson totally kicked my ass:
+ (EPFoobarMO *)foobarWithDefaultContext
return [NSEntityDescription insertNewObjectForEntityForName:@"Foobar" inManagedObjectContext: [[NSApp delegate] managedObjectContext];
I often forget that I’m a cretin preaching to a crowd of really smart people.)
I kid you not: NSManagedObject and Core Data are becoming some of my favorite coding structures/paradigms ever. (I suppose I have Wolf Rentzsch to thank; by the way, mogenerator v1.1 is out. Check it out.) It’s just so awesome – so nice not to have to futz around with NSUndoManager, NSCoding, and all the other minutiae that some brave souls worked with in years past.
I got rejected – not just deferred, rejected – from the University of Chicago. 😦 As such, I don’t really have time to write a very lengthy entry; therefore, I’ll just leave you with this little question/guide.
The official way of instantiating an instance/subclass of NSManagedObject is (I think) to use the NSManagedObject class method
initWithEntity:insertIntoManagedObjectContext:, like so: (we are assuming that there’s an NSManagedObjectModel and NSManagedObjectContext named
NSEntityDescription *e = [[model entitiesByName] objectForKey: @"Foobar"];
EPFoobarMO *foo = [[EPFoobarMO alloc] initWithEntity: e insertIntoManagedObjectContext: context];
Since they’re nice people, Apple gave us a convenience method:
EPFoobarMO *foo = [NSEntityDescription insertNewObjectForEntityForName: @"Foobar" inManagedObjectContext: context];
But if we’re sticking to the MVC paradigm (which we are, aren’t we?), one wants to put the initialization code for the EPFoobarMO object inside the EPFoobarMO .m/.h file.
+ (EPFoobarMO *)foobarWithContext:(NSManagedObjectContext *)context
// According to the docs the object returned is autoreleased
return [NSEntityDescription insertNewObjectForEntityForName:@"Foobar"
But it’s ugly to have to pass the NSManagedObjectContext to the initializer every time. We could stick it inside the app’s controller:
- (EPFoobarMO *) foobar
But that’s a flagrant violation of the MVC rules. (Of course, if you’re ignoring them, then this is an ideal solution. But down that way lies Nyarlathotep.)
Or we could resort to the insanity that is the C preprocessor. (I would give a code sample, but I don’t want to hate myself.)
Anyway, what do you think? Leave comments with your opinions or to alert me of any blatant inaccuracies.