Friday, November 6, 2009

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.

Thursday, January 15, 2009

Simple HOM

While it is good to see that Higher Order Messaging is still inspiring new work, I feel a bit guilty that part of that inspiration are sentiments such as the following:

"Still I have yet to find a simple implementation that I like and that does not use private methods. The last thing I want is a relying on classes which can break at any time."
Mea culpa.

While I did explain a bit why the current HOM implementation is a bit gnarly, code probably speaks more loudly than repeated mea-culpas.

So, without further ado, a really simple HOM implementation. An NSArray category provides the interface and does the actual processing:

@interface NSArray(hom)

-collect;

@end

@implementation NSArray(hom)

-(NSArray* )collect:(NSInvocation*)anInvocation
{
  NSMutableArray *resultArray=[NSMutableArray array];
  for (id obj in self ) {
    id resultObject;
    [anInvocation invokeWithTarget:obj];
    [anInvocation getReturnValue:&resultObject];
    [resultArray addObject:resultObject];
  }
  return resultArray;
}

-collect {
  return [HOM homWithTarget:self selector:@selector(collect:)];
}

@end
The fact that NSInvocation deals with pointers to values rather than values makes this a bit longer than it needs to be, but the gist is simple enough: iterate over the array, invoke the invocation, return the result.

That leaves the actual trampoline, which is really just an implementation detail for conveniently creating NSInvocation objects.

@interface HOM : NSProxy {
  id xxTarget;
  SEL xxSelector;
}

@end

@implementation HOM

-(void)forwardInvocation:(NSInvocation*)anInvocation
{
  [xxTarget performSelector:xxSelector withObject:anInvocation];
}

-methodSignatureForSelector:(SEL)aSelector
{
  return [[xxTarget objectAtIndex:0] methodSignatureForSelector:aSelector];
}

-xxinitWithTarget:aTarget selector:(SEL)newSelector
{
  xxTarget=aTarget;
  xxSelector=newSelector;
  return self;
}

+homWithTarget:aTarget selector:(SEL)newSelector
{
  return [[[self alloc] xxinitWithTarget:aTarget selector:newSelector] autorelease];
}

@end
This code compiles without warnings, does not use any private API, and runs on both Leopard and the iPhone. Github: https://github.com/mpw/HOM/.


EDIT (Aug 15 2015): Changed SimpleHOM download link to github repo.