People fight over languages all the time, but rarely do such things come to blows. When you’re the World’s Toughest Programmer, however, you can’t afford to pussyfoot around with things like rhetoric. So it was that I very nearly got into a fistfight over Objective C.
I was preparing for class, trying to ignore the punk ass kid bloviating on his hours of programming experience, until something he said caught my ear. “...but the worst language, the worst language, is Objective C.”
At this point I didn’t have a lot of experience with the language, but what I did know, I liked. So it was with honest surprise that I said, “Wait, really? You think Objective C is the worst language? Why? Is it the syntax? I know it’s weird, but it’s really readable.”
“Well,” he said, “it ain’t C.”
“But... it is C,” I said, taken aback. “It is exactly C. In fact it’s the only object-oriented language, as far as I know, that is implemented as a true superset of C, so the entirety of C is always at your disposal.”
Then, something occurred to me, and it was with dawning comprehension, and entirely without malice, that I said, “Oh wait, I get it. You don’t actually know anything about Objective C. You’re just talking out of your ass.”
Then he called me out. Here we were, in something that was at trying to pass as a college, and he called me out like we were on the playground in 6th grade. Again, you have to understand, I was talking not out of machismo, but out of a sincere desire to understand.
“You want to fight with me?” I asked, with genuine incredulity. “You actually want to get into a physical altercation with the biggest guy in this room over a programming language you don’t even know?”
And he actually came for me. It was only the appearance of the professor at that very moment that broke the boil into merely a simmering resentment, because the kid was a punk, but he was also a kiss-ass, and if there was anything he wasn’t going to do it was cause a ruckus in front of the teacher.
That said, I’m not going to try to convince you that Objective C is the best language, or that Cocoa is the best application framework. I’m simply going to tell you that, for me, they are. When I begged, I begged with PHP, ASP, SQL, XSL, JavaScript, Java, and even *shudder* C# .NET. When I chose, I chose Cocoa.
And so it is with the Apple spirit of never be satisfied with “best” that I present my short list of ways in which I think Cocoa could be improved. I don’t think anything I’m saying here is new. Certainly I’ve bandied these about with Wil, twitterstormed them with Wolf Rentzsch, and sent them in to Apple as my official wish list for Mac OS X 10.6 “Ocelot.”
While there are a few features I wouldn’t mind seeing added, what I really want is to give Cocoa a severe pruning. In other words, I want deprecations, deprecations, deprecations.
Lose the Optimizations
Cocoa is quite old, and has a lot of peculiarities that stem from the state of the metal back in NeXT days. The worst offenders are optimizations based on how expensive views used to be. Now, they mostly just complicate things and make certain aspects of UI programming needlessly complicated.
The most obvious example is NSCell and its subclasses. Most controls in the Application Kit consist of a single “heavyweight” view and one or more lightweight cells, which actually draw the UI and handle events. Controls typically duplicate their cells’ interfaces in an attempt to make them more bearable, but impedance mismatch between the two classes often renders this convenience somewhere between ineffective and harmful.
Let’s get rid of cells and rewrite all the standard controls to handle their own business. When, in the case of a complicated view like NSTableView, we need a lot of sub-controls, just use the standard view hierarchy or, if you want to be lightweight about it, layers. Certainly for single-celled controls like NSButton or NSTextField, we could afford to lose a lot of indirection.
This will give us exactly half as many classes to have to worry about, which, in the case of a very deep subclass like NSTokenField, can be very significant. Fewer classes means less time hunting bugs and poring over documentation, which means better applications faster—exactly the sort of thing Cocoa is meant to facilitate.
The basic idea is what you see should be what you get, even at the development level. You shouldn’t have to worry about some proxy object jumping in at the last minute and intercepting an event, causing inexplicable behavior (or lack thereof).
To that end, let’s retire the field editor. Not unlike cells, the idea of the field editor is that text containers are so amazingly expensive we can really only afford one. Whenever the user selects a text container, it’s secretly replaced with the field editor, which deals with the editing process. Then, when the user commits and moves on, the field editor transfers its knowledge to the real container and moves on.
This is a lot like trying to hold a conversation with someone by proxy. Often, you’d like to know about the conversation as it happens, not simply see the result. From a programming perspective, it makes it mighty difficult for an object to mind its business when its business is being dealt with by someone else. This seems like a basic violation of the personal responsibility of objects, and it sure makes it difficult to do any kind of custom implementation
Unify the Interface
Leopard unified the user interface, but the application programming interface remains as broken as ever. Much of this is a side effect of the evolution of Cocoa. You can see how API dating from 10.0 might not be aware of a class introduced in 10.2.7, but there’s no excuse for not updating the API in the intervening years.
I am talking, of course, about NSError. Any method that’s risky enough to go wrong a significant amount of the time should be returning an NSError by reference, as seen in my beloved NSXML’s nodesForXPath:error: and the hundreds of other methods that follow this same pattern. The trouble is, some of the older classes do not do this.
Typically we see things like NSFormatter’s getObjectValue:forString:errorDescription: that return an NSString by reference. NSFormatter is older than Lucas, but let’s get with the program. Deprecate getObjectValue:forString:errorDescription: and implement getObjectValue:forString:error:, much like what Leopard did for the NSFileManager classes, which used to eschew errors in favor of handlers, unlike every other class on the system.
Speaking of NSFormatter, can we agree that the primary purpose of a method should be manifest in its return value? One might expect getObjectValue:forString:error: to return, oh, I don’t know, the object value for a string. If you happen to know about the bizarre convention of starting method signatures with get, you might expect the return value to be the address of the pointer of an object value for a string. What you do not expect is to get a goddamned Boolean with the actual object value being returned by reference as the first argument. Whatever the reason for this:
- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
it needs to go away. With more and more people getting into Cocoa, it’s shit like this that makes things needlessly difficult. I don’t want to see our documentation looking like Java’s, with the word “deprecated” being used for punctuation, but damn.
Returning Booleans is for methods that start with the word is. If I want to know if an object did what I told it, I’ll check my error pointer. If I don’t see the suffix error: on a method signature, I don’t expect to get any guff. If I do see error:, I expect to get an NSError and nothing else.
NSAppleScript is terrible with this. It has methods like executeAppleEvent:error: that look like they should return an NSError reference, but instead return an NSDictionary reference. This is the worst possible thing it could do, because it not only behaves differently, it muddles the self-documenting nature of Objective C.
The whole point of Objective C’s controversial syntax is to keep us out of the documentation. We should be able to look at a method signature and know exactly what it does, just as we should be able to guess the method signatures of similar classes. I don’t use NSSet as much as I probably should, but I know if I want to know how many objects are in a set I should call count. How do I know this? Because that’s what I call on an NSArray.
So what the hell happened to Address Book? In terms of interface unity, ABMultiValue might just be the worst class in Cocoa. Why should querying the Address Book yield a collection seen nowhere else in the entire API? Whatever marginal convenience given the user by its few methods pales before the immense pain in the ass of having to open the documentation for some obscure, unexpected collection.
Even from Apple’s point of view, one more collection to maintain sure seems like a lot of extra work for nothing. Whoever signed off on this API addition had to have thought, “Hmmm, what if something happened to change the way collections work? We might forget this bastard class.” Skip ahead one operating system iteration, and guess which oddball collection class doesn’t implement fast enumeration?
Best Practices
I have a theory about Apple: there’s one engineering team that has an inexplicable hard-on for opaque proxy objects, and any project they get assigned to will be thus blighted until the next round of engineering shuffle, when the first task of the new team is to find an old priest, a young priest, and a bible.
I know Objective C has its own patterns, even while it turns its nose up at others. That said, Objective C is still an object-oriented language and would do well to behave as such. I like encapsulation as much as the next guy, but it’s not the only paradigm.
NSTreeController in Tiger was the poster child for the problem with proxies. In a very limited scope, you could do interesting things with trees, but in practice, you quickly ran into bugs and limitations. In the normal world of objects, armed with the flexibility of Objective C, it would have been trivial to change, fix, or extend this class into usability, but damn near everything about it was declared opaque, which made the class all but useless.
Which brings me to Core Data. For the record, I adore Core Data, but it demonstrates, directly, or indirectly, much of what is wrong with Cocoa. It violates many of the things I’ve already talked about. It doesn’t have anything so repugnant as NSTreeController’s node proxy, but it does hijack a lot of NSObject’s methods, declaring them off limits, which succeeds in limiting its usefulness, mucking up the interface, and sending us into the documentation.
The biggest problem is with entities. An entity describes some object, including certain basic properties like a name and an identifier, as well as a list of typed properties. You can create subentities that inherit the properties of their parent entities. In other words, an entity is a class, except it’s not. Threin lies the problem. Much like NSCell’s parallel universe to NSView, NSEntityDescription gives us a parallel universe to the basis of object-oriented programming.
The list of things not to subclass or override is enormous. Dire warnings about intricate optimizations and object life-cycle management send a very clear message: trust us. Abandon all control over your objects and give yourself to Core Data. We have provided alternate methods for the things you need to do. Exchange all of your outside currency for Core Data scrip. Shop at the company store. Obey. Obey.
Now, to be fair to Core Data, sexy things like properties didn’t exist in Tiger, when Core Data was born, and maybe they really do need to take over the object life cycle, given the concept of faulting versus normal deallocation, and maybe it’s worth it, after all, to give up control of your objects for all that Core Data gives you for free, but opacity breeds inflexibility, and when you run into the limits of what Core Data can do, things start to get very, very tricky.
For example, while obeisance to Core Data gets you data abstraction and undo management, it also gets you incompatibility with Spotlight, Quick Look, Time Machine, and FSEvents. None of that is Core Data’s fault per se. The trouble is all these new technologies rely on the file system, and Core Data is opaque to the file system.
Consider Delicious Library, with its media. In Core Data, every medium is a row in the table, which is great when you’re in Delicious Library, but when you’re in the file system your entire library is just one huge Core Data file, be it a property list, an SQLite database, or whatever. Want to use Spotlight to search for a book in Delicious Library? Want to use Quick Look to take a gander at the results of that search? Want to to use Time Machine to find that book before your cat stepped on your keyboard and deleted it?
Too bad. There are no books on your system. There is simply an opaque Core Data file. There is nothing to index or preview.
All that’s a walk in the park compared to what Core Data does to Time Machine. Understand that Time Machine is just a snapshot of your file system. The genius comes from the use of filesystem links to fill in for files that have not changed. If you have a hundred files on your drive through a hundred snapshots, you don’t want 10,000 files clogging up your drive. With Time Machine, if you’ve only changed one file each time, you only end up with 200 files.
Core Data is like zipping all those files into an archive. A change to any file is a change to the entire archive, which is roughly equivalent to having 10,000 files on your drive when you really only need 200. Change one letter in one record in a 700 MB library for each of a hundred snapshots and you’ve got 70 GB of Delicious Library clogging up your drive. Not even I like Delicious Library that much.
Of course, you can use Spotlight and Quick Look with Delicious Library 2, and backing up your library with Time Machine will not suck up all your disk space, but that’s only because we cheated. That is to say, we implemented Apple’s recommended workaround for this issue by writing a little shadow file for every item in your library into a special folder. Instead of addressing your data directly, the file system uses these proxy objects instead.
The trouble is, writing out a bunch of files kind of negates the whole point of using Core Data, because writing and maintaining two different data stores takes time. When Delicious Library is slow, it’s because it’s writing out all these files. Don’t even get me started about the code and man hours required to build, debug, and maintain this parallel system, because Core Data doesn’t do any of this automatically.
The upshot of all this complaining is this: Core Data needs to automatically index its records for the benefit of Spotlight. Those results should be navigable, ideally in the file system, as if the database were a folder. You should be able to Quick Look these items, and Time Machine should save the deltas and let you navigate that, again, like the database were a folder.
Now, this could all be accomplished by Spotlight writing out the shadow files automatically, but honestly, I think Apple can do better than that. I wouldn’t criticize them if I didn’t think they weren’t up to the task. I often tell people that if I didn’t like them, I wouldn’t take the time to insult them. So it goes with Apple, with Cocoa, and with Objective C. It’s the best: now let’s make it better.
New Features
I’d be happy with exactly zero new features in the next iteration of Cocoa, assuming all that energy went into fixing the things that are broken, outdated, or annoying. That said, there are a few things I wouldn’t mind seeing in the language and its APIs. Nothing too groundbreaking, either. These are just things I miss about Java, and I hate missing things about Java.
Objective C is all about flexibility, but not stupidly so. Yes, you can cast anything as id, but in real life we use static typing most of the time, because the compiler is good about warning us about picky little details. I’d like to see more of that, particularly with regard to collections.
In order to be generally useful, collections have to accept id, but in practice, you almost never mix types in a given collection. In Java 5, they introduced the ability to type collections, a feature known weirdly as “generics.” This is really just a compiler feature, which would be implemented as something like this:
NSMutableArray(NSString) *stringArray = [NSMutableArray array];
This array would throw an compiler error if you tried to insert something that was not statically typed as NSString, so [stringArray addObject:(NSNumber *)someNumber] would cause a compiler error. This is not unlike NSUserDefaults stringArrayForKey:, but as a feature of the collection. Alternately, or in addition, it could be added to collections themselves, so we’d get exceptions if anything that violated our assigned type tried to enter the collection.
Another compiler trick added to Java 5 is autoboxing, which is the ability to treat non-objects as objects without the explicit use of container classes. In other words, the compiler would see:
NSArray *integerArray = [NSArray arrayWithObject:(NSInteger)someInteger];
and convert it to:
NSArray *integerArray = [NSArray arrayWithObject:[NSNumber numberWithInteger:(NSInteger)someInteger]];
Then, when you tried to pull something like:
12 * [integerArray lastObject];
the compiler would convert that to:
12 * [[integerArray lastObject] integerValue];
This should also work with NSValue, so we could pass NSRects and such around without having to constantly deal with moving them in and out of objects.
Finally, why are collections mutually exclusive of one another? How nice would it be to simply expect some collection and not necessarily have to worry about what type of collection it is until runtime, if ever. Imagine if all collections were subclasses of the abstract superclass NSCollection, which implemented common functionality. So, you could have a method like:
- (NSCollection *)aBunchOfStuff;
and do this:
[[someObject aBunchOfStuff] count];
You could figure out the class via introspection, or better yet, NSCollection could implement a coercion method that would do the right thing, either implicitly, or explicitly:
[[someObject aBunchOfStuff] collectionByAddingContentsOfCollection:[otherObject aBunchOfStuff]];
or:
[[[someObject aBunchOfStuff] mutableSet] unionSet:[[otherObject aBunchOfStuff] set]];
Obviously there are going to be certain default behaviors, as happens if you use fast enumeration directly over a dictionary, but that’s OK. You can always find out if it’s a dictionary and call the proper dictionary methods to get the half you want.
One More Thing...
Could we please get a new icon for Cocoa? I’m referring to the logo image that always seems to show up in WWDC presentations on the subject. Java gets a nicely rendered coffee cup that always makes me want pie. Carbon has the cell from the periodic table, which has a simplicity and old school charm. We get a sad looking mug of cheap diner cocoa with a paltry sprinkling of mini marshmallows that looks simultaneously unprofessional and unappetizing. I know Apple doesn’t like to waste a lot of time with developer graphics *cough* Shark icon *cough* but damn.
Addenda
Or maybe not! Read my follow-up to this post: Let me Count the Ways.
A lot of other people also had something to say about this in the comments. Here are a few of my favorites...
Colin Barrett
I disagree about ditching NSCell entirely. I wish they would move the event handling code out of NSCell.
It would be quite nice to have a dumb, configurable object that JUST draws a control in whatever state you want in a view you specify, and can do so very quickly and efficiently.
NSCell comes so close, but utterly fails sometimes — try drawing the button on the right side of combo box. It also has one of the most confusing APIs known to man. The state masks combined with cell attributes, combined with under-documented convenience methods means I’ve spent way too much time in gdb trying to figure out what the crap is going on.
It is similarly baffling to me how poorly Core Data and Spotlight et al play together. Shadow trees on disk is kind of ridiculous, and why I ended up not using SQLite (or Core Data) for logging in Adium, and wrote a whole bunch of custom XML writers (fast, atomic appends to an XML file that’s well formed on disk at all times) and readers (generates SAX events starting at the end of the file and going backwards).
Should the new rallying cry be Fix Our Fucking Framework?
Mike Lee
-
It would be quite nice to have a dumb, configurable object that JUST draws a control in whatever state you want in a view you specify, and can do so very quickly and efficiently.
Except that controls are views, and views, by their very nature, draw themselves.
Random Lemur
Hey, great thoughts, but could you lose the profanity in your title? Profanity has its place, but it’s a dessert and not a main course. (Plus this particular profanity is, on its very face, pretty much the most offensive thing you can call someone.)
Thanks.
Brent S
Fuck that motherfucker before me. The name of your blog is perfect. Also, I didn’t understand any of your post, but the letters were pretty.
Mike Lee
Silly lemur, everyone knows that “cunt” is the worst thing you can call somebody ever. Furthermore, “motherfucker” is an obscenity, not a profanity.
Think of the title of this blog as a very clear statement that you had better have a good sense of humor and not take yourself too seriously, or you’re not going to have a good time here.
That said, if it helps your paws and whiskers, you’ll notice that Alison, which always has the latest entry, has a different title.
Ben Reubenstein
I am very new to Objective-C but have run into these weird unexpected things on very simple tasks, good call. Also, for aspiring programmers, are their resources you would recommend? I am looking for a good book. Also, Fuck that Motherfucker above me. He can suck my balls.
Random Lemur
Yeah, so did you cap that dude after class? Obviously, he needs a little bit of attention.
And also, I know nothing about coding, or programming, or anything like that, and I was able to enjoy most of your article, filling in through context what the details I was not able to grasp. Thanks for writing an article that even I can enjoy.
Chris Hanson
It’s not a Core Data problem, it’s a Spotlight and Time Machine don’t play well with the rest of the universe problem.
After all, even if Core Data changed to accommodate this design fl—, er, “choice” by the Spotlight and Time Machine designers, there’s still the problem of every single other multi-element file ever causing exactly the same issue.
Think of those poor folks using Entourage with multi-GB mail databases that will be copied over, and over, and over... Think of those people using Photoshop to tweak one layer in a multi-hundred-MB image that then re-copies the entire image.
The fact that Colin felt he had to write his own persistence mechanism rather than using SQLite or Core Data is just another symptom of this problem.
Mike Lee
-
for aspiring programmers, are their resources you would recommend?
The best programming book I have ever read was “Head First Java.” My mother could learn to program from that book. Sadly, it’s about Java. Happily, the concepts still apply.
As for learning Objective C itself, I think Apple’s own documentation on the subject is top notch. I also think, as one who owns a lot of technical books, that technical books are overrated. I think it’s better to charge into writing a (small) application and learn as you go than to read about programming, trying to remember everything at once.
-
what happened after class with the guy
By the end of class, it had hardened into a solid grudge. I wasn’t going to make anything more of it. I don’t beat people up for being stupid; there aren’t enough hours in the day.
-
It’s not a Core Data problem
This is the party line down at Core Data HQ, just as the party line at Spotlight HQ is that there is no problem because you can just make shadow files, etc. I would call it a mutual incompatibility between large, opaque files and file system-based technology. Certainly I don’t blame Core Data, other than to note that going Core Data means going opaque.
That said, I believe a solution to this problem lies within Apple’s abilities, and while I don’t think it will be any fun, I also don’t think it need be particularly difficult. Both sides need to get together, shake hands, and come up with a solution. Let Entourage and Photoshop continue to suck, while Core Data shoots right past into awesomeness.
lemurs
I prefer “cuntface” as can be used just like “motherfucker”, but more offensively.
As in: “Don’t be such a cuntface,” or “Have any of you motherfuckers seen my cuntfaced papwerwork?”
Try it out, it’s fun!
Teemu A-P
As a newcomer to Cocoa I’ve wondered about the error handling. Explicit error codes seem to be favored over exception use, although for me the latter seem better fit.
Why’s this? Just a historical thing or is there something deeper going on?
Localized NSError objects look like a mistake to me: the part of code raising the error may not know the best user-understandable explanation to include. The calling part (error handler) may have access to more context and can format the error display better...
Guess I’m Fuzzy
I think the criticisms are fair, though I suspect that the NSCell/NSView dichotomy is still important. They could fix the interface and cheat behind the scenes, though, probably.
Generics, however, are the worst thing about Java 5 (gotta love the type erasure bugs), and the last thing I’d want to see in ObjC. In fact, I’d argue for the removal of static typing from ObjC before I’d argue for the addition of generics. If you’re coding in Ruby or Python you don’t miss static typing (though you may write more programmer tests to make up for it). If you’re coding in Java 5, you do miss knowing which implementation of a method will actually be called at runtime, and you do miss building warning-free code (since it’s now impossible to have a fully type-safe program).
Teemu A-P
One thing that the language is sorely missing is proper namespacing.
Stefan
-
It would be quite nice to have a dumb, configurable object that JUST draws a control in whatever state you want in a view you specify, and can do so very quickly and efficiently.
Try the HIThemeDraw* calls, they do exactly that.
Andy Lee
Excellent points — even if you do choose to omit the hyphen from “Objective-C” — about stuff I didn’t even realize was bugging me.
Reminds me a bit of Michael McCracken’s “The Editing Pass.”
I agree I could do without more Cocoa features in the next rev, and would be happy for Apple to do an editing pass over the APIs.
Mike Lee
-
Explicit error codes seem to be favored over exception use
With explicit errors, you have to try to crash your program. With thrown exceptions, you have to try to not crash your program. Most problems just aren’t so dire to be worth a crash.
-
Localized NSError objects look like a mistake to me
I think the piece of code generating an error should probably have the best idea of why that error occurred. In the odd case where this is not so, the error presentation chain is free to deal with the error in whatever way it sees fit.
-
I suspect that the NSCell/NSView dichotomy is still important
A lot of people seem to suspect that, yet nobody can really tell me why this would be so. Views are no longer particularly heavyweight objects, and layers can do any lightweight rendering (including hit testing) that cells do now.
The only possibility I see are for things that are naturally given to cells, like the table view, but even then, layers.
-
I’d argue for the removal of static typing from ObjC
Pussyfeathers. Static typing is and has always been optional in Objective C. Realistically, you rarely need dynamic typic, and having the compiler catch stupid errors is a good thing.
-
If you’re coding in Java 5
A lot of people seem to hate the implementation of generics in Java and hold that against the whole idea of statically typed collections, which is a shame, because static typing (when optional) is your friend.
-
One thing that the language is sorely missing is proper namespacing
So people say, and theoretically I agree with them, but realistically, I don’t think they’re as necessary as people make them out to be. I’ve never run into a namespace collision in Objective C and I find XML namespaces to be a pain in the ass much of time.
-
Even if you do choose to omit the hyphen from “Objective-C”
In my book, I used the hyphen. Then I saw some Apple stuff that didn’t use the hyphen, which makes a kind of sense, insofar as “objective” is an adjective and all. I thought for this entry, I’d try it on and see how I liked it. The jury is still out.
mikeash
The reason NSCell still matters is because NSView pretty much enforces a strict 1:1 mapping between data objects and view objects, whereas NSCell doesn’t.
NSTableView is the perfect example. Imagine a table view with a million rows. Cocoa handles this pretty well right now, because it has one cell per column, only draws what’s visible, and only asks the data source for that data. Now imagine it implemented with NSView; suddenly you need one view per row. Views may not be as expensive as they once were but creating a million NSView instances is still a very expensive thing to do. Suddenly hit testing, clipping, drawing, etc. become vastly more expensive because those algorithms have to deal with the 999,9980 NSViews which aren’t visible as well as the 20 which are. And you either have to fetch all million values from the data source at once or you need to radically change some APIs, because right now the standard NSControls have no provision for lazy loading of data.
The presence of NSCell simply makes things more flexible. It’s not a holdover, it’s a fundamental framework design choice which has a lot of benefits. I think that things could be improved a lot in this area, but not by getting rid of NSCell. One idea which I haven’t fleshed out at all would be to reduce the number of classes on the view side of things, so that you end up with something like a generic NSControl which is capable of holding any cell and working with it correctly. This would eliminate much of the parallel hierarchy that people dislike so much while preserving all the benefits of cells.
As for the rest of the post, much is right on, much is wrong (generics? ugh) and some is slightly misdirected. Your desire for interchangeable collections is a good one, but we already have it to a large degree. You can pass around collections and as long as you limit what you do with them, they Just Work. For the things you want to do which aren’t currently supported, nothing requires a common NSCollection superclass, and it could all be implemented in your own code using categories without a great deal of effort.
Andy Lee
-
Now imagine it implemented with NSView; suddenly you need one view per row. Views may not be as expensive as they once were but creating a million NSView instances is still a very expensive thing to do.
?? I think you’d only need one view per visible row per column. This could still end up being hundreds of views, or even thousands on a big screen, but those would be rare cases, and it’s still nothing like a million.
I also don’t see why the NSTableView APIs would have to change at all (well, except for the parts that refer to cells). Everybody’s datasource methods would be fine just as they are -- only the internals of NSTableView would have to change to stuff cell values into views.
mikeash
Sure, you could handle things by limiting your views to just what’s visible. But now you’ve made things much more complicated by requiring that NSTableView have a bunch of logic to create and destroy these views on demand. You also get problems with creating new views, since views are inherently difficult to copy due to all of the outside connections they have. Views with nontrivial internal state, like the selection of NSTextViews, will lose that as they disappear from the screen, leading to surprising behavior. Something like an NSColorWell will mysteriously cease to be linked to the color panel if scrolled off screen. Cells avoid this by virtue of being prohibited from exhibiting such complicated behavior in the first place, so it’s not a great win, but the point is that views will behave very differently in this environment, trading off cell versus view to view in context X versus view in context Y.
NSCollectionView works this way, as I understand it, and has at least some of the issues described above as a result. The true test of the idea can probably be seen by watching what the limitations and problems end up being for this class as time goes on.
The ability to access control drawing and behavior outside of the view hierarchy is just a useful thing overall, and it’s good design. This separation isn’t inherently bad, the only thing that’s bad is all the redundancy that came out of it. This redundancy isn’t inherent to the concept, and could be done away with without removing the separation.
charles
Re CoreData and Spotlight:
I think Apple could leverage here a concept that is quite slick, that of “package” for documents. Then CoreData could create package documents, and implement some support for blobs along the SQlite database file (or the xml or binary file).
And maybe packages could be made that a little nicer to other filsystems by making them disk images instead, and have Spotlight/TimeMachine be able to see through dmgs.
charles
btw, the Lemur CATTA is a cool idea and works fine.
However, maybe you should put it at the bottom of the page, otherwise hard to find in the middle of a long post and long comments. And then, to submit 2 comments, you have to click again on Alison. Maybe this is on purpose, but the point is to make submitting comments annoying only to people not interested in what you say, and adding extra non-disciminatory annoying steps goes against the concept, doesn’t it?
Random Lemur
Apple already has package documents — rtfd is one such document format.
Jonathan Grynspan
It seems you’ve read my mind. I loathe NSCell.
Andre
I agree. ABMultiValue is the freaking devil!! I hate that class!
And autoboxing sounds great. I don’t know about generics though.... the point of allowing id in arrays is as long as any type of object fulfills the API you want to use (say NSStrings’ length method for example) then there should be no problem putting other objects as long as they fulfill the “API Contract.”
I think a modification to your idea for generics like behavior for Cocoa, would be something like generics but instead of restricting to a class, restrict to an API contract... IOW a category like so:
NSMutableArray(<protocol>) *windowControllers = [NSMutableArray array];
What do you think?? Because in this case, if a developer creates a new window controller class, for example, they won’t get some weird error when they want to substitute their own (that fixes bugs or something) class for the standard one.... IOW I think we should be better to limit based on “API Contract” that makes the whole thing more flexible and more “cocoa-ish...”
And yes, NSCollection FTW!!
(Andre... I don’t know what you had in there for the protocol but if you email it to me I will fill it in. -- Mike)
Random Lemur
I would like to see a separation of data structure from algorithm. Just about the only thing I like about C++ is the STL’s clean separation of the two. For example, I would like to see a series of algorithms, for example [CommonAlgorithm sort:(NSCollection *)] as opposed to having such algorithms be methods of a data structure. The introduction of the foreach loop was a step in this direction.
The creation of configurable StringTokenizer, Regex, and Parser classes. But I’m working on those at the moment.
Rick Altherr
For the record, there are 5 engineers that work on Shark. There are no marketing people or artists. We even write our own documentation. So, yes, the logo is a bit rough on the edges, but we’re quite proud of it.