Friday, November 6, 2009

Blocked-C

Update: It appears that the original article has been removed, and has been superseded by material at: http://developer.apple.com/mac/articles/cocoa/introblocksgcd.html. The original article had more on the Cocoa block APIs and gave a refreshingly honest assessment of the for-loop vs. Block-iteration comparison.

While the news that Apple is adding blocks to C and Objective-C in the SnowLeopard time frame has been around for some time, a recent article shed some light on the actual API.

While there probably are some places where Objective-C blocks can be useful, I am not really impressed. In the following samples, red is used to show noise, meaning code that is just there to make the compiler happy.



NSMutableArray *filteredItems= [NSMutableArray array];
[items enumerateObjectsWithOptions:0 withBlock:
    ^(id item, NSUInteger index, BOOL *stop) {
        [filteredItems addObject:[item stringByAppendingString:@"suffix"]];
    }
];

As you can see, the version using blocks is very, very noisy, both syntactically and semantically, especially compared with the HOM version:
[[items collect] stringByAppendingString:@"suffix"];

No prizes for guessing which I'd prefer. To put some numbers on my preference: 234 characters vs. 52, 19 tokens vs. 3, 5 lines vs. 1. In fact, even a plain old C for-loop is more compact and less noisy than our "modern" blocked version:
NSMutableArray *filteredItems= [NSMutableArray array];
for (int i=0; i < [items count]; i++ ) {
     [filteredItems addObject:[items objectAtIndex:i] stringByAppendingString:@"suffix"];
    }
];

Why not Objective-C?

Patrick Logan can't understand why projects use C++ rather than Ojective-C. Neither can I.

For the 95% (or more) of code that isn't performance sensitive, it gives you expressiveness very close to Smalltalk, and for the 5% or less that need high performance, it gets you the performance and predictability of C.

Sunday, September 20, 2009

Cocoa(touch) memory management is as easy as 1-2-3

There is a common misconception that Cocoa memory management is hard. It's not.

  1. Use auto-generated accessors religiously
  2. Release your instance variables in dealloc
  3. Always use convenience methods to create objects
Wow, that wasn't too hard!

Sunday, February 8, 2009

Objective-XML-5.0.1

Just pushed out a minor bugfix release to Objective-XML-5.0:
  • Re-enabled character-set conversion code that had gotten disabled
  • Fixed a compile-error for some targets
  • Other minor improvements
Download here: http://www.metaobject.com/downloads/Objective-C/Objective-XML-5.0.1.tgz

Sunday, January 25, 2009

Objective-XML 5.0

I've just pushed out a new release of Objective-XML, with some pretty significant new features.

Incremental parsing

This feature, which was already discussed a little in an earlier post, is now available in an official release. In short, Objective-XML will now stream data from network data sources (specified by URL) and produce results incrementally, rather than reading all of the data first and then parsing it. This can make a huge difference in responsiveness and perceived performance for slow networks. CPU and memory consumption will be slightly higher because of extra buffering and buffer stitching required, so this should only be used when necessary.

Static iPhone library

Although Objective-XML has always been compatible with the iPhone, previous releases required copying the pre-requisite files into your project. This burden has now been eased by the inclusion of a static library target. You still need to copy the headers, either MPWMAXParser.h or MPWXmlParser.h (or both).

Unique keys

Previous releases of Objective-XML had an -objectForTag:(int)tag method for quickly retrieving attribute or element values.


enum songtags {
  item_tag=10, title_tag, category_tag	
};
...
  [parser setHandler:self forElements:[NSArray arrayWithObjects:@"item",@"title",@"category",nil]
          inNamespace:nil prefix:@"" map:nil tagBase:item_tag];
...
-itemElement:(MPWXMLAttributes*)children attributes:(MPWXMLAttributes*)attributes parser:(MPWMAXParser*)p
{
   ...
   [song setTitle:[children objectForTag:title_tag]];
   ...

Objective-XML adds an -objectForUniqueKey:aKey method that removes the need for these additional integer tags.
...
  [parser setHandler:self forElements:[NSArray arrayWithObjects:@"item",@"title",@"category",nil]
          inNamespace:nil prefix:@"" map:nil];
...
-itemElement:(MPWXMLAttributes*)children attributes:(MPWXMLAttributes*)attributes parser:(MPWMAXParser*)p
{
   ...
   [song setTitle:[children objectForUniqueKey:@"title"]];
   ...


In addition to providing faster access, the integer tags also served to disambiguate tag names that might occur in multiple namespaces. To handle these conflicts, there now is a -objectForUniqueKey:aKey namespace:aNamespace method. The namespace objects required for this disambiguation process are now returned by the -setHandler:... and -declareAttributes:... methods, which were previously void.

Default methods

One of the attractive features of DOM parsers is that they do something useful "out of the box": point a DOM parser at some XML and you get back a generic in-memory representation of that XML that you can then start taking apart. However, once you go down that road, you are stuck with the substantial CPU and memory overheads of that generic representation.

Streaming parser like SAX or MAX can be a lot more efficient, but it takes a lot more time and effort until achieving a first useful result. Default methods overcome this hurdle by also delivering an immediately useful generic representation without any extra work. Unlike a DOM, however, this generic representation can be incrementally replaced by more specialized and efficient processing later on.

Tuesday, January 20, 2009

Cocoa HTML parsing with Objective-XML

Although Objective-XML's MPWSAXParser mostly provides NSXMLParser compatibility it also provides a number of useful additional features. Among these features is the ability to parse HTML files via the settings of two flags: enforceTagNesting and ignoreCase. By default, these are on and off, respectively, which gives you strict XML behavior. However, by setting enforceTagNesting to NO and ignoreCase to YES, you get a SAX parser that will happily and speedily process HTML.

Sunday, January 18, 2009

Semantic Noise

Martin Fowler and Gilad Bracha write about Syntactic Noise, making similar points and using similar typographical techniques as I did in my HOM paper.
By Syntactic Noise, what people mean is extraneous characters that aren't part of what we really need to say, but are there to satisfy the language definition. Noise characters are bad because they obscure the meaning of our program, forcing us to puzzle out what it's doing.
Couldn't have said it better myself, so I'll just quote Martin Fowler. Syntactic noise is one of the reasons I think neither the for(each) statement nor the blocks added to Objective-C are particularly good replacements for Higher Order Messaging.
newArray = [existingArray map:^(id obj){ return [obj  stringByAppendingString:@"suffix"]; }];
newArray = [[existingArray map] stringByAppendingString:@"suffix"]];

To me, that extra syntax is quite noisy, though the noise isn't, in fact, just syntactic. We also have to introduce, name and even correctly type a completely redundant stand-in (obj) that we don't really care about. Introducing extra entities is semantic noise. Apart from having to puzzle out what that extra entity is (and that it is, in fact, redundant) every time we read the code, it also brings us back to "element at a time" programming and thinking.