FROM : Chris Hanson
DATE : Mon Jun 09 20:02:16 2008
On Jun 9, 2008, at 10:24 AM, John Engelhart wrote:
>> This is not a bug. This is fundamental to how object-oriented
>> programming works! You should always be able to pass an instance
>> of a subclass wherever an instance of the superclass is expected.
>
> You're mistaken. You have statically typed the object.
John, it is you who are mistaken. You're mistaken about what
"statically typed" means in Objective-C. It does not mean "I will
always pass an instance of exactly NSArray", it means "I will always
pass an instance of NSArray or a subclass."
That's all it means.
> Just as '+(NSArray *)array' does not mean "and any possible
> subclasses"
In fact, it WOULD mean that. It means "returns an instance of
NSArray, or any subclass thereof, that senders should treat as an
NSArray."
For example, if -[NSArray array] were declared as above, it could
still perfectly validly return a shared instance of a special
_NSEmptyArray subclass of NSArray.
All your code will know or care about is that what it gets back is
usable as an NSArray.
>>> If one applies the 'attribute only applies to the class it was
>>> specified for' rule:
>>>
>>> By statically typing the class to NSArray, you have certified to
>>> the compiler that no other object type will be received as an
>>> argument. When you passed it an object of a different type, even
>>> a subclass, you broke your promise to the compiler.
>>
>> This is simply wrong.
>
> You're encouraged to read the section "Enabling Static Behavior -
> Static Typing" in the Objective-C manual. This is what allows for
> subclasses to return different types for the same method. By
> statically typing a declaration as NSArray, you've told the compiler
> that the object is a NSArray (only) class object, and only the
> methods for NSArray apply.
John, with all due respect, I do know what I'm talking about here --
I've been working with Objective-C on NeXT and Mac OS X for 11 years
now -- and it is you who are wrong about this.
Whether you're dealing with Objective-C, C++, or Java, instances of
subclasses are always substitutable for instances of their superclass
where the type system is concerned.
> The fact that object instantiation methods return 'id' and not the
> base class are further evidence that this is indeed the case.
The reason these kinds of methods have a return type of (id) is that
there is no way to say "returns an object of the receiver's class."
For example, +[NSArray array] returns (id) rather than (NSArray *)
because otherwise +[NSMutableArray array] would require a separate
declaration (NSMutableArray *). Rather than have a large number of
separate declarations, these methods return (id).
> You also can't send messages declared in a subclass of NSArray to a
> 'NSArray *array;' object without getting a warning. Again, further
> evidence that the compiler believes that only the explicitly named
> class is applicable, and not 'any and all subclasses'.
You misunderstand. You can *assign* an instance of any subclass to a
variable typed as a class. The compiler will warn you about any
messages you send that aren't in the interface of the typed class,
however.
Thus you can say, perfectly validly:
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
NSArray *array = mutableArray;
This is perfectly fine. However, the compiler will give you a warning
if you try to send any non-NSArray messages to "array."
-- Chris
DATE : Mon Jun 09 20:02:16 2008
On Jun 9, 2008, at 10:24 AM, John Engelhart wrote:
>> This is not a bug. This is fundamental to how object-oriented
>> programming works! You should always be able to pass an instance
>> of a subclass wherever an instance of the superclass is expected.
>
> You're mistaken. You have statically typed the object.
John, it is you who are mistaken. You're mistaken about what
"statically typed" means in Objective-C. It does not mean "I will
always pass an instance of exactly NSArray", it means "I will always
pass an instance of NSArray or a subclass."
That's all it means.
> Just as '+(NSArray *)array' does not mean "and any possible
> subclasses"
In fact, it WOULD mean that. It means "returns an instance of
NSArray, or any subclass thereof, that senders should treat as an
NSArray."
For example, if -[NSArray array] were declared as above, it could
still perfectly validly return a shared instance of a special
_NSEmptyArray subclass of NSArray.
All your code will know or care about is that what it gets back is
usable as an NSArray.
>>> If one applies the 'attribute only applies to the class it was
>>> specified for' rule:
>>>
>>> By statically typing the class to NSArray, you have certified to
>>> the compiler that no other object type will be received as an
>>> argument. When you passed it an object of a different type, even
>>> a subclass, you broke your promise to the compiler.
>>
>> This is simply wrong.
>
> You're encouraged to read the section "Enabling Static Behavior -
> Static Typing" in the Objective-C manual. This is what allows for
> subclasses to return different types for the same method. By
> statically typing a declaration as NSArray, you've told the compiler
> that the object is a NSArray (only) class object, and only the
> methods for NSArray apply.
John, with all due respect, I do know what I'm talking about here --
I've been working with Objective-C on NeXT and Mac OS X for 11 years
now -- and it is you who are wrong about this.
Whether you're dealing with Objective-C, C++, or Java, instances of
subclasses are always substitutable for instances of their superclass
where the type system is concerned.
> The fact that object instantiation methods return 'id' and not the
> base class are further evidence that this is indeed the case.
The reason these kinds of methods have a return type of (id) is that
there is no way to say "returns an object of the receiver's class."
For example, +[NSArray array] returns (id) rather than (NSArray *)
because otherwise +[NSMutableArray array] would require a separate
declaration (NSMutableArray *). Rather than have a large number of
separate declarations, these methods return (id).
> You also can't send messages declared in a subclass of NSArray to a
> 'NSArray *array;' object without getting a warning. Again, further
> evidence that the compiler believes that only the explicitly named
> class is applicable, and not 'any and all subclasses'.
You misunderstand. You can *assign* an instance of any subclass to a
variable typed as a class. The compiler will warn you about any
messages you send that aren't in the interface of the typed class,
however.
Thus you can say, perfectly validly:
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
NSArray *array = mutableArray;
This is perfectly fine. However, the compiler will give you a warning
if you try to send any non-NSArray messages to "array."
-- Chris






Cocoa mail archive

