CoreFoundation Bugs

Abstract:

It would be beneficial not only for developers working in the CoreFoundation layer, but also for those working with technologies which depend on CoreFoundation all the way up to AppKit if some problems in the headers were corrected. They relate to developing interfaces and implementations to Apple's C-level frameworks using BridgeSupport (and its Objective-C runtime symbol generation), HeaderDoc XML generation, and anomalies in CoreFoundation naming conventions.

Separate bugs for the problems/suggestions with BridgeSupport and HeaderDoc have been filed to coordinate with this one.

This document bases its remarks on facilities in Mac OS X 10.5.6

Table of Contents:
BridgeSupport:

BridgeSupport is critical for scripting language integration with Mac OS X and very useful for those generating function wrappers. Not only for PyObj and RubyCocoa but also for all other scripting languages shipped with Mac OS X (including AppleScript, Perl, Tcl, and PHP). Also for those developing custom interfaces in C, C++, and/or Objective-C.

But BridgeSupport is currently being hit below the belt because several CF headers don't use typedef'd function callbacks for their context structures. Consequently, BridgeSupport creates a virtually useless Obj-C runtime symbol for such items -- meaning that they can't be mapped to something meaningful for developers bridging to CoreFoundation (sample output is illustrated in the summary). For example in CFRunLoop.h:

typedef struct {
    CFIndex version;
    void *info;
    const void *(*retain)( const void *info );
    void (*release)( const void *info );
    CFStringRef (*copyDescription)( const void *info );
    Boolean (*equal)( const void *info1, const void *info2 );
    CFHashCode (*hash)( const void *info );
    void (*schedule)( void *info, CFRunLoopRef rl, CFStringRef mode );
    void (*cancel)( void *info, CFRunLoopRef rl, CFStringRef mode );
    void (*perform)( void *info );
} CFRunLoopSourceContext;

the callbacks need to be supplied like those for CFAllocator so the BridgeSupport generation has a name to work with rather than the un-helpful Objc-C runtime symbol.

typedef const void * (*CFAllocatorRetainCallBack)( const void *info );
typedef void (*CFAllocatorReleaseCallBack)( const void *info );
typedef CFStringRef (*CFAllocatorCopyDescriptionCallBack)( const void *info );

The net result of such sins of omission is a waste of time (=money) for other developers (including Apple developers) who have to then resort to extraordinary means to get things working as if BridgeSupport had generated useful names in the first place. 

HeaderDoc:

Another problem is creating supporting documenation for the derived interfaces.

The following Terminal call will emit a cferrs.txt file showing where CoreFoundation header formatting should be corrected. (I get 32 warnings on Mac OS X 10.5.6).

cd /System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers;headerdoc2html -d -o ~/Desktop/cfdocs `ls *.h` 2>~/Desktop/cferrs.txt;

These warnings cause problems for the documentation folks (like wasting time manually correcting things which could be generated automatically if the headers were fixed). In some cases they also show where HeaderDoc comments are missing entirely. For instance, the top level explanation of CoreFoundation fundamentals (like Create/Copy/Release behavior) isn't apparent in either CoreFoundation.h or CFBase.h. This Terminal call shows the remarks:

cd /System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers;headerdoc2html -d CFBase.h CoreFoundation.h;

Naming Conventions:

It should be brought to the attention of whoever is responsible for the following in CFNotificationCenter.h that CoreFoundation naming conventions for constants are not the same as those for Cocoa. CoreFoundation thru Carbon uses the prefix 'k' for enums and defines, etc.

enum {
    CFNotificationSuspensionBehaviorDrop = 1,
    CFNotificationSuspensionBehaviorCoalesce = 2,
    CFNotificationSuspensionBehaviorHold = 3,
    CFNotificationSuspensionBehaviorDeliverImmediately = 4
};
typedef CFIndex CFNotificationSuspensionBehavior;

About this particular item, what is good about it is the sub-word ordering -- logical in the sense that the defining variant is at the end rather than say kCFNumberSInt64Type in CFNumber.h (i.e., should be kCFNumberTypeSInt64). The observation of this discrepancy -- at least in my mind -- shows a lack of rigor in the CoreFoundation naming conventions which ought to be addressed at some point. One reason such regularity is benefical is that it's easy to arrive at a standardized auto-mapping of symbol names to a format viable for other languages.

For instance to arrive at C++ or Tcl :: namespace conventions the more desirable auto-translation is to something like: ::k::CFNumber::Type::SInt64 rather than ::k::CFNumber::SInt64::Type (which puts the cart before the horse).

Similarly for AppleScript where a dual implementation is needed to have coordination between AppleScript and its binary implementation, the developer wants to end up with both typeSInt64 and SInt64. The "typeXXX" form is a shared naming convention between large portions of the CoreServices, ApplicationServices, and Carbon frameworks.

Apart from the constants, I think it would be good to put some function names under scrutiny. For example: CFStringCreateWithFormat(), CFURLCreateFromFSRef(), and UTCreateStringForOSType() basically have the same 'create' implication but there appears to be no rhyme or reason why one or another has 'with', 'from', or 'for'. It would be a lot easier for CoreFoundation users if one or another of these terms was settled on and applied consistently.

Summary:

This article gives a brief overview of some CoreFoundation areas which could be improved to augment its interoperability with other system facilities (i.e. "plays well with other children"). At first glance it might seem that everything would be peachy if the items mentioned above were followed through. But, just as CoreFoundation could improve in this area, both BridgeSupport and HeaderDoc could be better cooperating citizens. For straight-ahead bugs in BridgeSupport, it's unconscionable to see things like the following in CoreFoundationFull.bridgesupport:

<constant name='kCFTypeArrayCallBacks' declared_type='CFArrayCallBacks' type='{_CFDictionaryValueCallBacks=i^?^?^?^?}' type64='{_CFDictionaryValueCallBacks=q^?^?^?^?}' const='true'/>

<enum name='kCFCoreFoundationVersionNumber10_5_4' value='476.13999999999999'/>

where it's obviously confused about CFArray and CFDictionary callbacks and inexplicably assigns a floating point number to an enum.

But the gross inefficiency for the system here is that while ostensibly dealing with the same area of mapping C interfaces to XML, their schemas for the strictly "C" portions (i.e. not documentation) are completely different. Moreover, it's not even a matter of tossing a coin and saying "ok, we'll settle on BridgeSupport or a HeaderDoc schema" — the fact is, neither of them is an optimal representation for coordinating with other areas of the system.

For mapping C languages to XML, the correct way to proceed is to follow the C standard categorization. Probably a C99 standard such as the one located at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf. Following the standard can only bode well for intergating with technologies Apple is clearly intent on using such as llvm's analytical and optimization facilities.

The XML C representation of both BridgeSupport and HeaderDoc should be one and the same and a much closer match to the standard's categories. An example is sketched below.

C code:

#include <stdio.h>

int main( int argc, char *argv[] ) {
    
    int err = 0;
    int value = 42;
    
    fprintf( stdout, "The answer is: %d\n", value );
    
    return err;
}

XML Rendering:

<ctox::translation-unit version="1.0" xmlns:ctox="http://www.aker.ca/ctox/">
 <function-definition>
  <type-specifier value="int"/>
  <declarator>
   <direct-declarator-function>
    <direct-declarator-identifier value="main"/>
    <parameter-list>
     <parameter-declaration>
      <type-specifier value="int"/>
      <declarator>
       <direct-declarator-identifier value="argc"/>
      <declarator>
     <parameter-declaration>
     <parameter-declaration>
      <type-specifier value="char"/>
      <declarator>
       <pointer/>
       <direct-declarator-list>
        <direct-declarator-identifier value="argv"/>
       <direct-declarator-list>
      <declarator>
     <parameter-declaration>
    <parameter-list>
   <direct-declarator-function>
  <declarator>
  <compound-statement>
   <declaration>
    <type-specifier value="int"/>
    <init-declarator-list>
     <declarator>
      <direct-declarator-identifier value="err"/>
     <declarator>
     <initializer>
      <expression-assignment value="0"/>
     <initializer>
    <init-declarator-list>
   <declaration>
   <declaration>
    <type-specifier value="int"/>
    <init-declarator-list>
     <declarator>
      <direct-declarator-identifier value="value"/>
     <declarator>
     <initializer>
      <expression-assignment value="42"/>
     <initializer>
    <init-declarator-list>
   <declaration>
   <expression-statement>
    <expression>
     <expression-function>
      <expression-identifier value="fprintf"/>
      <expression-identifier value="stdout"/>
      <expression-str value=""The answer is: %d\n"/>
      <expression-identifier value="value"/>
     <expression-function>
    <expression>
   <expression-statement>
   <return-statement>
    <expression>
     <expression-identifier value="err"/>
    <expression>
   <return-statement>
  <compound-statement>
 <function-definition> 
<translation-unit>
Author:

Philip Aker  <[email protected]>


Valid XHTML 1.0 Strict

§