Professional Web Applications Themes

CFArray vs CFMutableArray - Mac Programming

Given a reference to some unidentified Core Foundation object in C, how can I determine whether that object is a CFArray or a CFMutableArray? They are both doented to have the same type ID, making it impossible (AFAICT) to tell them apart. -- -Thomas <http://www.bitjuggler.com/>...

  1. #1

    Default CFArray vs CFMutableArray

    Given a reference to some unidentified Core Foundation object in C, how
    can I determine whether that object is a CFArray or a CFMutableArray?
    They are both doented to have the same type ID, making it impossible
    (AFAICT) to tell them apart.

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  2. #2

    Default Re: CFArray vs CFMutableArray

    In article <250420041714309311%spam.me>,
    Thomas Reed <spam.me> wrote:
     

    I believe you are supposed to know depending on how you created it. How did you
    get into a situation where you don't know?

    meeroh

    --
    If this message helped you, consider buying an item
    from my wish list: <http://web.meeroh.org/wishlist>

    Miro Guest

  3. #3

    Default Re: CFArray vs CFMutableArray

    In article <mit.edu>,
    Miro Jurisic <org> wrote:
     
    >
    > I believe you are supposed to know depending on how you created it. How did
    > you
    > get into a situation where you don't know?[/ref]

    Well, some background details: I'm trying to write a set of wrapper
    classes for the Core Foundation in REALbasic, which allows me to call
    through to Carbon routines. Ideally, these classes should be
    incredibly easy for the developer to use, without needing to pester him
    with such things as "Hey, buddy, what exactly did you store in this
    array? I know it's some kind of string, but I can't tell exactly what
    type."

    What I was trying to do is instantiate the appropriate class depending
    on the return result of CFGetTypeID. But then I discovered that the
    mutable variants have the same type IDs as their non-mutable
    counterparts.

    It seems that this defeats the entire purpose of even having a type ID.

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  4. #4

    Default Re: CFArray vs CFMutableArray

    In article <260420040818245911%spam.me>,
    Thomas Reed <spam.me> wrote:
     

    To make things even better, when you call CFMutableArray functions on an
    immutable CFArray, the behavior is undefined.

    This probably means that the best you can do is have a single RB class which
    represents both Foo and MutableFoo, always assume you have a Foo to begin with,
    and call CFFooCreateMutableCopy the first time you need to have a mutable object.

    meeroh

    --
    If this message helped you, consider buying an item
    from my wish list: <http://web.meeroh.org/wishlist>

    Miro Guest

  5. #5

    Default Re: CFArray vs CFMutableArray

    In article <mit.edu>,
    Miro Jurisic <org> wrote:
     

    Yup, that's what I saw in the docs. Someone on the RB mailing list
    suggested I just act like they're interchangable, but I didn't think
    that would be a good idea.
     

    That's probably a wise idea. Is it safe to assume that a
    CFMutableString, for example, is a "subclass" of CFString? That is,
    can I always rely on being able to call CFStringCreateMutableCopy, and
    any other function that acts on a CFString, on a CFMutableString?

    If so, I'll just always create a non-mutable class instance in such
    cases, and give each class a GetMutableCopy function.

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  6. #6

    Default Re: CFArray vs CFMutableArray

    Thomas Reed <spam.me> wrote:
     
    >
    > Yup, that's what I saw in the docs. Someone on the RB mailing list
    > suggested I just act like they're interchangable, but I didn't think
    > that would be a good idea.

    >
    > That's probably a wise idea. Is it safe to assume that a
    > CFMutableString, for example, is a "subclass" of CFString? That is,
    > can I always rely on being able to call CFStringCreateMutableCopy, and
    > any other function that acts on a CFString, on a CFMutableString?
    >
    > If so, I'll just always create a non-mutable class instance in such
    > cases, and give each class a GetMutableCopy function.[/ref]

    There is no way to check for mutability. This is because of the class
    cluster architecture. You might want to read up on class clusters; your
    use of the naive term "subclass" suggests that you need to. This entire
    problem, by the way, has been discussed ad nauseam on the cocoa users
    list at Apple. m.


    --
    matt neuburg, phd = com, http://www.tidbits.com/matt/
    AppleScript: The Definitive Guide
    http://www.amazon.com/exec/obidos/ASIN/0596005571/somethingsbymatt
    Read TidBITS! It's free and smart. http://www.tidbits.com
    matt Guest

  7. #7

    Default Re: CFArray vs CFMutableArray

    In article <1gcuco3.14v6zk51r5xfk2N%com>, matt neuburg
    <com> wrote:
     

    Yup, I get that idea by now.
     

    That's the reason I put "subclass" in quotes. I'm aware that
    CFMutableString is not a subclass of CFString. There's no reason to
    throw around negative words like "naive".

    What I want to determine is if it is safe to pass CFMutableStrings to
    routines that take CFStrings.
     

    I'm not on that list. I don't do much Cocoa work. Perhaps I can find
    it in the archives, though...

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  8. #8

    Default Re: CFArray vs CFMutableArray

    In article <260420041202073644%spam.me>,
    Thomas Reed <spam.me> wrote:
     

    Yes. (If it wasn't, mutable CF objects would be a lot less useful than
    they are....)

    -Eric

    --
    Eric Albert stanford.edu
    http://rescomp.stanford.edu/~ejalbert/
    Eric Guest

  9. #9

    Default Re: CFArray vs CFMutableArray

    Thomas Reed <spam.me> wrote:
     

    Hey, I don't know what your quotes mean. If you don't mean "subclass",
    don't say "subclass", quoted or otherwise.
     

    It's not a negative word. Often, closing one's eyes to extra
    complications and subtleties is good. m.


    --
    matt neuburg, phd = com, http://www.tidbits.com/matt/
    AppleScript: The Definitive Guide
    http://www.amazon.com/exec/obidos/ASIN/0596005571/somethingsbymatt
    Read TidBITS! It's free and smart. http://www.tidbits.com
    matt Guest

  10. #10

    Default Re: CFArray vs CFMutableArray

    In article <260420041041350108%spam.me>,
    Thomas Reed <spam.me> wrote:
     
    >
    > That's probably a wise idea. Is it safe to assume that a CFMutableString,
    > for example, is a "subclass" of CFString? That is, can I always rely on
    > being able to call CFStringCreateMutableCopy, and any other function that
    > acts on a CFString, on a CFMutableString?[/ref]

    Yes.
     

    I wouldn't do that because it requires your clients to do the right thing. I
    would instead have a private boolean which starts off false and indicates
    whether the CFArray represented by your VB object is known to be mutable; then
    in every function that requires a mutable array, do:

    MakeMutable();

    and let MakeMutable be like this:

    void
    MyCFArrayWrapper::MakeMutable()
    {
    if (not mKnownMutable) {
    CFMutableArrayRef mutableCopy = ::CFArrayCreateMutableCopy(mMyArray);
    CFRelease(mMyArray);
    mMyArray = mutableCopy;
    mKnownMutable = true;
    }
    }

    This also guarantees that you do not call CFArrayCreateMutableCopy more than
    once for a given CFArray wrapper object.

    hth

    meeroh

    --
    If this message helped you, consider buying an item
    from my wish list: <http://web.meeroh.org/wishlist>

    Miro Guest

  11. Moderated Post

    Default Re: CFArray vs CFMutableArray

    Removed by Administrator
    Miro Guest
    Moderated Post

  12. #12

    Default Re: CFArray vs CFMutableArray

    In article <mit.edu>,
    Miro Jurisic <org> wrote:
     
    >
    > I wouldn't do that because it requires your clients to do the right thing. I
    > would instead have a private boolean which starts off false and indicates
    > whether the CFArray represented by your VB object is known to be mutable;
    > then
    > in every function that requires a mutable array, do:[/ref]

    I don't think I adequately explained myself. What I'm doing now is,
    whenever I load a CF object from a collection, I create a non-mutable
    class instance (for example, a CFString or CFArray). This is safe,
    since there's no problem treating a mutable object as a non-mutable
    one.

    Now, if the user wants a mutable object, then they need a completely
    different class -- CFMutableString or CFMutableArray, in the case of
    the example above. So, what they'd do is call CFString.GetMutableCopy,
    which would use CFStringCreateMutableCopy, to get a CFMutableString
    object. So there wouldn't be multiple conversions (unless the client
    decided to throw away the result of the last GetMutableCopy and call it
    again) or reliance on the client not to misbehave. They'd be using a
    completely different REALbasic object, containing a mutable copy of the
    original.

    This seems to be working well in my testing. Is there a hidden
    land-mine that I am not seeing, though?

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  13. #13

    Default Re: CFArray vs CFMutableArray

    In article <270420040844502286%spam.me>,
    Thomas Reed <spam.me> wrote:
     

    Nope. If your goal is to map the RB APIs as close to CF APIs as possible, that's
    a good solution. I was suggesting an approach which reduces complexity of the RB
    API at the expense of not being as closely matched to the CF API

    meeroh

    --
    If this message helped you, consider buying an item
    from my wish list: <http://web.meeroh.org/wishlist>

    Miro Guest

  14. #14

    Default Re: CFArray vs CFMutableArray

    In article <mit.edu>,
    Miro Jurisic <org> wrote:
     

    Okay, cool, thanks for the help!

    --
    -Thomas

    <http://www.bitjuggler.com/>
    Thomas Guest

  15. #15

    Default Re: CFArray vs CFMutableArray

    com (matt neuburg) wrote in message news:<1gcuco3.14v6zk51r5xfk2N%com>... 
    > >
    > > Yup, that's what I saw in the docs. Someone on the RB mailing list
    > > suggested I just act like they're interchangable, but I didn't think
    > > that would be a good idea.
    > > 
    > >
    > > That's probably a wise idea. Is it safe to assume that a
    > > CFMutableString, for example, is a "subclass" of CFString? That is,
    > > can I always rely on being able to call CFStringCreateMutableCopy, and
    > > any other function that acts on a CFString, on a CFMutableString?
    > >
    > > If so, I'll just always create a non-mutable class instance in such
    > > cases, and give each class a GetMutableCopy function.[/ref]
    >
    > There is no way to check for mutability. This is because of the class
    > cluster architecture.[/ref]

    I'm not sure what you mean by that. As far as I know, the current
    (flawed) implementation do not provide a public API allowing to check
    for mutability, but I don't think this is implied by the class cluster
    architecture at all.

    Best,

    -- Philippe Mougin
    http://www.fscript.org
    The open source scripting environment for Cocoa
    Philippe Guest

  16. #16

    Default Re: CFArray vs CFMutableArray

    In article <google.com>,
    org (Philippe Mougin) wrote:
     
    > >
    > > There is no way to check for mutability. This is because of the class
    > > cluster architecture.[/ref]
    >
    > I'm not sure what you mean by that. As far as I know, the current
    > (flawed) implementation do not provide a public API allowing to check
    > for mutability, but I don't think this is implied by the class cluster
    > architecture at all.[/ref]


    General "check for mutability and behave accordingly" is not a safe &
    healthy thing to do (even if you called the private APIs to determine it
    accurately).

    You should only depend on the declared return value of a function, and
    not some sort of "probing" of the object. Consider a routine that is
    declared to return an immutable string, but in fact, returns a mutable
    string. It may be designed such that it can't handle that string be
    modified by something else. For example, suppose there is something
    like a static text UI element that has the bounds of the string as well
    as the string itself. It's "get title" routine may return the mutable
    stirng it uses (but declared as immutabled), but all modification of the
    title go through a "set title" routine that updates the bounds. If you
    just look at the string as being mutable, you might be tempted to change
    it - and suddenly the bounds no longer matches the title (and strange
    and unexpected bugs will appear - one can imagine worse things happen
    with more complex things like text editors).

    So just because a routine returns a mutable string doesn't mean that it
    should be treated as mutable. It should be treated as however it was
    declared.
    Glenn Guest

  17. #17

    Default Re: CFArray vs CFMutableArray

    Glenn Andreas <reply> wrote in message news:<mpls.visi.com>... 
    > >
    > > I'm not sure what you mean by that. As far as I know, the current
    > > (flawed) implementation do not provide a public API allowing to check
    > > for mutability, but I don't think this is implied by the class cluster
    > > architecture at all.[/ref]
    >
    >
    > General "check for mutability and behave accordingly" is not a safe &
    > healthy thing to do (even if you called the private APIs to determine it
    > accurately).
    >[/ref]

    I agree that checking for mutability does not ensure in itself that
    what you do with the object is safe (but neither does any other
    run-time introspection technique). However, this does not imply that
    it is not possible to do safe things based on such run-time checks (I
    mean, from the fact that some usages are unsafe does not follow the
    fact that all usages are unsafe). There is a whole space of safe
    things you can do based on such checks (including, for instance, what
    the original poster had in mind).

    (Well, doing the check is actually not safe since Core Foundation
    seems to not publicly supports this feature, but that's another
    problem).
     

    I don't get the first part of this assertion, at least taken as a
    general rule (is that what you meant?). For instance, CFArray's
    CFArrayGetValueAtIndex() method declare that its return value is of
    type const void *. If I was to only depend on the statically declared
    type for the return value, I would not be able to do very interesting
    things with the value. (BTW, I would have the same problem in Cocoa.
    For instance, in Cocoa Java, NSArray's objectAtIndex() method declare
    that its return value is of type "Object". If I was to only depend on
    this declared type I would be only able to call methods declared in
    the Object class).

    It seems to me that it all comes to the way we interpret static typing
    on the return value of a function. I think it should be interpreted as
    a commitment from the function to return a value of a given run-time
    type (or of a derived type, in the case of an API which has the notion
    of derived type like Core Foundation). I don't think it should be
    interpreted as a requirement about what the caller should do with the
    returned value, because then it becomes impossible to design useful
    APIs using static typing.

    Seems to me that if we want to express such requirements, we should
    express them in the doentation of the function (or through
    doented conventions).
     

    Yes, I agree. In addition to the run-time type of our data we have to
    take into consideration many other things in order to act in a correct
    way.
     

    Suppose I want to implement a routine that, depending on various
    things at run-time, wants to sometimes return a non-mutable string,
    and sometimes returns a mutable string (that the caller would be
    allowed to modify). How should I statically type the return value of
    this function according to your usage of typing?

    Best,

    Philippe Mougin
    http://www.fscript.org
    The open source scripting environment for Cocoa
    Philippe Guest

  18. #18

    Default Re: CFArray vs CFMutableArray

    In article <google.com>, 
    >
    > I don't get the first part of this assertion, at least taken as a
    > general rule (is that what you meant?). For instance, CFArray's
    > CFArrayGetValueAtIndex() method declare that its return value is of
    > type const void *. If I was to only depend on the statically declared
    > type for the return value, I would not be able to do very interesting
    > things with the value. (BTW, I would have the same problem in Cocoa.
    > For instance, in Cocoa Java, NSArray's objectAtIndex() method declare
    > that its return value is of type "Object". If I was to only depend on
    > this declared type I would be only able to call methods declared in
    > the Object class).[/ref]

    "id" in Objective C is a generic "anything" value (much like void *).
    If something returns an id (or void *) that pretty much means that there
    is no knowledge of the object (for example, collections can hold any
    kind of object, so of course they will return id).

    If I put something in the collection, then I can use my external
    knowledge about what is in the collection. If the routine is declared
    to return a collection of, say, immutable strings, I know that
    objectAtIndex will return an immutable string (in C++ it might have been
    declared as NSArray<NSString> but there is no way to specify such typing
    unless one makes subclasses of NSArrays that return NSStrings). If the
    collection is an arbitrary collection from who knows where, then I know
    pretty much nothing about what is in it (other than it being an "id" - I
    can probably assume that it is at least an NSObject in the case of Cocoa
    collection classes), and so should do much with it.
     

    OTOH, if something is definited as returning an immutable object, you
    should treat it as such, even if it is actually a mutable object (ISTR
    that some CF objects are actually mutable or not just by a flag - so
    they could even dynamically change between mutable and immutable, as
    opposed to others where mutable is declared as a subclass of immutable).

     
    >
    > Suppose I want to implement a routine that, depending on various
    > things at run-time, wants to sometimes return a non-mutable string,
    > and sometimes returns a mutable string (that the caller would be
    > allowed to modify). How should I statically type the return value of
    > this function according to your usage of typing?[/ref]

    How would the caller know if they should be allowed to modify it then?
    I'd make two routines - one that returns the mutable version (if
    possible) and a second that returns the immutable version.

    If I saw a routine that returns an "id" then I know that it is a generic
    object - usually something that I provided in the first place (such as
    collection classes) and so I should know what it is, otherwise I don't
    know.

    If it explicitly says "mutable" or "immutable" then treat it as such (or
    be prepared to crash/have hard to track down bugs/etc...).

    Anything else seems like a bug waiting to happen.
    Glenn Guest

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139