Is there anything like a generic list in Cocoa / Objective-C?
Asked Answered
E

4

30

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.

Enloe answered 27/4, 2009 at 14:6 Comment(1)
Objective-C is a system based on protocol (interface) conformance, rather than type-relationships. IMO, what you really mean to ask is: is there some way for the compiler to instantiate collection types such that all elements of the collection conform to a given protocol (interface).Jotham
E
34

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.

Ehrenburg answered 27/4, 2009 at 14:6 Comment(12)
Also, if you need more advanced operations, read up on -mutableArrayValueForKey:Ehrenburg
-1 Strongly Disagree - denying that adding C# generics to Objective C wouldBlunder
... be a definite improvement. Language support for strong typing and dynamic typing are complementary techniques. Prediction: Objective C will implement C# style generics one day.Blunder
Generics are not a weak design, wanting them is not a sign of weak design. They just happen not to apply to Objective-C. The rest of your answer is helpful, however the opening statement is completely incorrect and misleading.Acrylyl
Well since this was a Cocoa question, my answer was specific to Cocoa!Ehrenburg
Generic lists are a fine idea, and a strong design. Heterogeneous lists on the other hand, are a terrible idea.Provocative
I wish Objective C had generics, it would help understand others peoples code so much easier. It's a time saver. I don't see it as a weak design at all.Oao
Obj-C and C#/Java folks are talking aside each-other on this issue. Java-style generics, which force collections to contain only objects derived from a specific base class are a bad idea in Objective-C, because Obj-C is a language based on protocol (interface) compatibility. (Sometimes called duck typing, because if it quacks like a duck it's a duck) HOWEVER, Obj-C could benefit from parametric protocol conformance. With this collections could be declared to allow only elements conforming to specific protocols. Helping turn runtime errors into compile time errors.Jotham
So your take on this is "This is unnecessary and wanting it is a sign of weak design. Why would you need it when you can do it yourself by defining a cumbersome extra class instead whose whole purpose is to simulate a generic array (for one particular type only) in many, many times as many lines of code?" That seems incredibly asinine.Markova
I'm not suggesting people effectively recreate large chunks of the NS(Mutable)Array API on a regular basis. There's generally only a few methods needed, and this tends to be part of some wider class for holding other properties tooEhrenburg
I thought List have performance improvements in some scenarios where inserting items into the middle of the collectionCanonicity
@Canonicity sounds like you're thinking of a Linked List? If so, that has basically nothing to do with the topic at hand.Ehrenburg
M
9

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

Maestro answered 27/4, 2009 at 14:9 Comment(0)
B
3

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.

Backbreaker answered 14/3, 2013 at 18:48 Comment(3)
Thanks for posting your answer! Please be sure to read the FAQ on Self-Promotion carefully. Also note that it is required that you post a disclaimer every time you link to your own site/product.Hannover
Thanks for pointing that out. I was quite unsure how to do this or whether it is considered too spammy. Right now I am busy but I will rework the answers according to the guidelines in a couple of hours.Backbreaker
Excellent! Your last two answers are decent, because they seem to address the question, you've included some good information (not just "see this project here" and a feature list). Just add the disclosure, and they are just fine. thanks again! Oh, also; just FYI; do be careful about posting exact copies of answers; These seem to be good enough for their questions, but be sure to try to tailor answers to the question specifically.Hannover
J
0

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.

Jotham answered 27/4, 2009 at 14:6 Comment(1)
"In fact, looking at actual types is a very very bad practice in Obj-C and in highly discouraged". Could you expand on that? All the standard data objects are implemented with inheritance, not protocols. Take for Example NSDecimalNumber : NSNumber : NSValue : NSObject. Or, NSString which doesn't provide a protocol either. Thus, of the two compile-time options, isKindOfClass: can be used while conformsToProtocol: can't. How is that bad practice?Backbreaker

© 2022 - 2024 — McMap. All rights reserved.