(Newb) Populate NSMutableDictioanry with NSArray

  • I came across tutorial code that looked sort of like this:

    NSMutableDictionary * myCollection;
    myCollection = [[NSArray alloc] initWithObjects:@"a", @"b", @"c", nil];

    The types are not the same. So my first question is, is this a bug?
    And if so, why didn't the compiler catch it? I come from C# so unless
    NSMutableDictionary inherits NSArray this logic would not compile.

    If it is not a bug, can someone confirm that NSDictionary is not just
    used for key/value pairs but as simple list types, too? Otherwise, why
    would myCollection above be declared as an NSMutableDictionary?

    Thanks,
    Jon
  • 8/31/08 2:34 AM, also sprach <jon...>:

    > NSMutableDictionary * myCollection;
    > myCollection = [[NSArray alloc] initWithObjects:@"a", @"b", @"c", nil];
    >
    > The types are not the same. So my first question is, is this a bug?
    > And if so, why didn't the compiler catch it? I come from C# so unless
    > NSMutableDictionary inherits NSArray this logic would not compile.

    Yes, it is a "bug". Because the return type of -initWithObjects is "id",
    which can represent any object, the compiler can't know that the types are
    incompatible.

    IIRC, you should get a compiler warning if you call a method that only
    NSArray implements, such as -objectAtIndex:, on the myCollection object.

    HTH,

    Keary Suska
    Esoteritech, Inc.
    "Demystifying technology for your home or business"
  • On Sun, Aug 31, 2008 at 4:34 AM, Jon Davis <jon...> wrote:
    > I came across tutorial code that looked sort of like this:
    >
    > NSMutableDictionary * myCollection;
    > myCollection = [[NSArray alloc] initWithObjects:@"a", @"b", @"c", nil];
    >
    > The types are not the same. So my first question is, is this a bug? And if
    > so, why didn't the compiler catch it? I come from C# so unless
    > NSMutableDictionary inherits NSArray this logic would not compile.
    >
    > If it is not a bug, can someone confirm that NSDictionary is not just used
    > for key/value pairs but as simple list types, too? Otherwise, why would
    > myCollection above be declared as an NSMutableDictionary?

    The important thing to understand about this case is that Objective-C
    does not have constructors as are found in certain popular object
    oriented languages. The "alloc" and "initWithObjects:" methods you're
    calling are just regular old methods. Although they create a new
    object for you, there's nothing special about them, or different from
    other methods.

    With that in mind, let's look at the declaration of the
    "initWithObjects:" method:

    - (id)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;

    And right there is your answer as to why you didn't get an error. It's
    typed to return "id", which of course is Objective-C speak for "any
    object". It's never an error, or a warning, to assign a value of type
    id to a more specific type. So your assignment of a value of type id
    to a variable of type NSMutableDictionary is perfectly valid.

    This just raises a new question, though: why does this method return
    "id" instead of NSArray *? The answer to this is subclasses, of which
    there is a great example in the form of NSMutableArray. Imagine if the
    method was typed to return NSArray *. Then you wrote code like this:

    NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"a",
    @"b", nil];

    This is perfectly legal code. But the compiler will whine at you.
    You're taking a value of type NSArray *, and assigning it to
    NSMutableArray *. Since NSMutableArray is a more specific type than
    NSArray, this assignment is considered unsafe, and you get a warning.
    But the code is perfectly fine. To avoid this problem, and to allow
    initializers to work with subclasses, they generally return "id"
    rather than a specific class type.

    Objective-C is pretty different from C#. In particular, its type
    system is a lot more dynamic and runtime oriented. The compiler will
    only catch superficial errors for you at compile time, as compared to
    environments like C# where compile time type checking is much more
    rigorous. Opinions vary as to which is better. Personally speaking,
    I've never had a type-based bug in Objective-C code that a stricter
    language would have caught but which took me a long time to find in
    Objective-C. These things tend to show up almost immediately in
    testing. And while they can be confusing if you're just starting out,
    with a little experience they tend to be easy to track down.

    Mike