views:

95

answers:

2

I have a function which returns CFTypeRef. I have no idea what it really is. How do I determine that? For example it might be a CFStringRef.

+3  A: 

CFGetTypeID():

if (CFGetTypeID(myObjectRef) == CFStringGetTypeID()) {
  //i haz a string
}
Dave DeLong
Yes, what about the rest of CFTypes? There are lots of them, can't do it for each one.
Nick Brooks
Actually, it was a string.
Nick Brooks
+1  A: 

The short answer is that you can (see Dave DeLongs answer). The long answer is that you can't. Both are true. A better question might be "Why do you need to know?" In my opinion, if you can arrange things so that you don't need to know, you're probably going to be better off.

I'm not saying that you can't do it, or even that you shouldn't. What I am saying is that there are some hidden gotchas when you start down this path, and some times you're not really aware of what all the unstated assumptions are. Unfortunately, programming correctly depends on knowing all the little details. Off the top of my head, here's a few of the potential gotchas:

  • To the best of my knowledge the set of Core Foundation types has increased in each major OS release. Therefore each major OS release has a superset Core Foundation types of the previous releases, and likely a strict superset at that. This is "observed behavior", and not necessarily "guaranteed" behavior. The important thing to note is that "things can and do change", and all things being equal, the easier and simpler solutions tend not to take this in to account. It is generally considered poor programming style to code something that breaks in the future, regardless of the reason or justification.

  • Because of Toll-Free Bridging between Core Foundation and Foundation, just because a CFTypeRef = CFStringRef does not mean that a CFTypeRef ≡ CFStringRef, where = means "equal to" and means "identical to". There is a distinction, which may or may not be important depending on context. As a warning, this tends to be where the bugs roam freely.

    For example, a CFMutableStringRef can be used where ever a CFStringRef can be used, or CFStringRef = CFMutableStringRef. However, you can not use a CFStringRef everywhere a CFMutableStringRef can be used for obvious reasons. This means CFStringRef ≢ CFMutableStringRef. Again, depending on the context, they can be equal, but they are not identical.

    It is very important to note that while there is a CFStringGetTypeID(), there is no corresponding CFMutableStringGetTypeID().

  • Logically, CFMutableStringRef is a strict superset of CFStringRef. It would follow, then, that passing a bona fide immutable CFStringRef to a CFMutableString API call would cause "some kind of problem". While this may not be true now (i.e., 10.6), I know for a fact that the following was true in the past: The CFMutableString API calls did not verify that "the string argument" was actually mutable (this was actually true for all types that made a distinction between immutable and mutable). The checks were there, but they were in the form of debug assertions that were disabled on "Release" builds (in other words, the checks were never performed in practice).

    This is (or possibly was) officially not considered to be a bug, and the (trivial) mutability checks were not done "for performance reasons". No "public" API is provided to tell the mutability of a CFString pointer (or mutability of any type). Combined with Toll-Free bridging, this meant that you could mutate immutable NSString objects, even though the NSMutableString APIs did perform a mutability check and caused "some kind of problem" when trying to mutate an immutable object. Flavor with the fact that @"" constant strings in your source are mapped to read-only memory at run time.

    The official line, as I recall, was "not to pass immutable objects, either CFStringRef or NSString, to CFMutableString API's, and further more, it was a bug to do so". When it was pointed out that there might be some security related issues with this stance (never mind the fact that it was fundamentally impossible), say if anything ever made the mistake of critically depending on the immutability of a string, especially "well known" strings, the answer was "the problem is theoretical and nothing will be done at this time until a workable exploit can be demonstrated."

    Update: I was curious to see what the current behavior is. On my machine, running 10.6.4, using CFMutableString API's on an immutable CFString causes the immutable string to become essentially @"", which is at least better than what it did before (<= 10.5) and actually mutate the string. Definitely not the ideal solution, has that bitter real world taste to it where its only redeeming quality is that it is "the least worst solution".

So remember, be careful in your assumptions! You can do it, but if you do, it's more important that you not do it wrong. :) Of course, a lot of "wrong" solutions will work, so the fact that things are working is not necessarily proof that you're doing it right. Good times!

Also, in a Duck Typed system it is often considered bad form, and possibly even a bug, to "look too closely at the type of an object". Objective-C is definitely a Duck Typed system and this unquestionably bleeds over in to Core Foundation due to the tight coupling of Toll-Free bridging. CFTypeRef is a direct manifestation of this Duck Type ambiguity, and depending heavily on the context, may be an explicit way of saying "You are not supposed to be looking too closely at the types".

johne
wow, that's a long answer. +1
Nick Brooks
The reason I need to know is because I retrieve a property from IO registry which can be a number of things and I can't determine what it is.
Nick Brooks