Question

What I really like in C# are generic lists. A list that can contain only one type of objects. Is there something like a generic list in Cocoa/Objective-C? As far I only know NSArray who will take a pointer to any object.

Was it helpful?

Solution

Wanting this in a Cocoa app is often a sign of a weak design.

NSArray is immutable, so it will not "take a pointer to any object" and presumably already contains the correct objects when handed to you. What I assume you're more worried about is an NSMutableArray where you think other parts of your code might add the wrong sort of object. But have a look at Cocoa itself; it's incredibly rare to expose a mutable array as part of a class's design.

Instead, you generally expose an NSArray and a couple of methods for modifying that array. Something along the lines of:

@class Foo : NSObject
- (NSArray *)bars;
- (void)addBar:(Bar *)bar;
- (void)removeBar:(Bar *)bar;
@end

This generally stops wrong objects being inserted simply by having a compiler warning, and then of course you can add assertions within -addBar: and -removeBar: if you wish too.

OTHER TIPS

Objective-C doesn't support generic programming. You could always use Objective-C++ and an STL list.

Generic NSArrays can be realized by subclassing NSArray, and redefining all provided methods with more restrictive ones. For example,

- (id)objectAtIndex:(NSUInteger)index

would have to be redefined in

@interface NSStringArray : NSArray

as

- (NSString *)objectAtIndex:(NSUInteger)index

for an NSArray to contain only NSStrings.

The created subclass can be used as a drop-in replacement and brings many useful features: compiler warnings, property access, better code creation and -completion in Xcode. All these are compile-time features, there is no need to redefine the actual implementation - NSArray's methods can still be used.

It's possible to automate this and boil it down to only two statements, which brings it close to languages that support generics. I've created an automation with WMGenericCollection, where templates are provided as C Preprocessor Macros.

After importing the header file containing the macro, you can create a generic NSArray with two statements: one for the interface and one for the implementation. You only need to provide the data type you want to store and names for your subclasses. WMGenericCollection provides such templates for NSArray, NSDictionary and NSSet, as well as their mutable counterparts.

No, Objective-C does not currently support parametric typing for collection elements.

However, this topic is more complex than the question or existing answers admit..

Parametric-Typing for collections in Objective-C would not be the same as Generics in C#/Java. For example, it is unlikely you would ever see Objective-C add the capability to assure every object added to a collection IS an NSArray type or subtype. Instead, Objective-C could (and IMO should) have the ability to assure every object in a collection CONFORMS to a protocol/interface. (i.e. that it implements a set of required methods)

Why?

Objective-C is a language built on protocol (interface) compatibility, NOT subtyping relationships. That is, objects are compatible if they have all the right methods, we don't look at or care about their actual types. In fact, looking at actual types is a very very bad practice in Obj-C and in highly discouraged. This notion is sometimes called "Duck Typing", because if it quacks like a duck, it's a duck. We don't care if it literally inherited from some specific duck or not. This prevents you from being saddled by someone elses implementation hierarchy. -- The result is that as long as an object coming out of the list has a draw:: method it works, we don't actually care if it is a subclass of some specific JimmyDrawableBase object.

This not only makes code more reusable, but it also encourages a slightly different (more functional?) type of problem decomposition, because you can't rely on objects being derived from a given base class and thus having a bunch of your base-class implementation forced into them.

I personally think it would be nice for the Obj-C compiler to have parametric checking of PROTOCOL *CONFORMANCE*. That is, to make a NSMutableArray which requires all objects placed in it conform to a given protocol (i.e. have a given set of required methods).

Sometimes even this more-flexible protocol-conformance checking is resisted by dynamic programming folks, and with sound reasons. Programmers often have a way of over-specifying conformance requirements.

For example, you might require a list contain objects conforming to the NSArray protocol/interface, but you might ACTUALLY only call two of those methods. This is over-conformance. Someone who wishes to stick a compatible item in your array is forced to implement a ton of methods you are not actually calling -- at least not yet (see next).

Google Go tries to solve this problem by inferring structural compatibility. That is, if you call draw() on items coming out of a list, then the compiler assures everything going into a list contains a draw() method. If it does not contain a draw() method, it's a compiler error to put it into the list. This prevents the code from simply causing the same error to occur at runtime. The problem with this is that it only works for whole-program compilation. If Google-Go could compile modular DLLs (which it can't), then it would run into the problem that there isn't a way for me to say objects in the list need to support a specific interface of three methods, even though I'm not calling them today, because I might call them in the future.

Between those two solution likes the tradeoff and the truth.

Personally, I would like to see Objective-C add parametric protocol conformance, so I could ask the compiler to assure the contents of a particular collection always conform to a given set of protocols.

I would also like the compiler to help me avoid over-conformance. If I'm not calling methods in those protocols on objects, it should generate errors/warnings telling me so. If I want to keep them in the protocol even though I'm not using them, I should have to explicitly make a declaration for each method in the protocol that it "might be used in the future, so elements all need to supply it now". This at least makes the process of over-conformance require MORE work, instead of Java/C# where it requires less work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top