Re: Bug in GCC 3.1?
Re: Bug in GCC 3.1?
- Subject: Re: Bug in GCC 3.1?
- From: email@hidden
- Date: Mon, 06 May 2002 15:35:38 -0700
Thomas Lachand-Robert wrote:
|I have found a problem that look like a bug in GCC 3.1, but maybe I just
|don't understand something.
|If you write in an Obj-C class:
|
|-(void) bar:(id<NSMutableCopying>)t { /*whatever */; }
|
|-(void) foo:(id<NSCopying>)t {
| [self bar:t];
|}
|then the compiler will complain in foo as follows:
|warning: object does not conform to the `NSMutableCopying' protocol
I replied:
|No, the compiler is behaving as it should. Declaring an argument as "id"
|does *not* mean to suppress type checking. It means merely that the
|argument a pointer to an Objective-C object whose exact type is
|unspecified.
He replied:
|That's what I meant. This doesn't explain why [self bar:(id)t] doesn't
|work, since NOW the object type is unspecified as you say.
But "bar:" requires an object that *is* specified, at least to the extent of implementing the NSMutableCopying protocol. The problem is precisely that "t" *is* completely unspecified; "bar:" requires at least a little specification. The compiler has no idea whether "t" implements NSMutableCopying or not, which "bar:' says is required, so it complains. The cast doesn't add any new information (since it still says the passed object is a completely-unspecified "id"), so the warning remains. (Do keep in mind that the message is a *warning*, the compiler saying nothing more than "this is technically legal, but it doesn't look right.")
I wrote:
|If you try to cast the argument to id<NSMutableCopying>, you're just
|writing explicitly what the compiler's doing anyway when it calls "bar:",
|so nothing has really changed.
He replied:
|But the cast doesn't work, either. I get the same error message, though
|for any other type, using an explicit cast shut up the compiler.
The cast doesn't change anything because, again, the cast does nothing that the compiler wouldn't have done anyway. In both cases, the compiler is warning you that an id doesn't implement the NSMutableCopying protocol, although "bar:" expects it to do so. Making the cast explicit doesn't change what "bar:" requires. The warning is produced because you're passing a plain, protocol-less id to a routine that expects an object implementing a certain protocol. The cast doesn't affect that.
I wrote:
|> Overall, it looks like you could benefit by reading more about how
|> protocols fit in with Objective-C.
He replied:
|I have read almost everything existing about protocols (that's not a lot),
|and still don't understand what happens here. However, you look as
|confused as I am, so... Thanks to have tried to help, anyway.
Actually, I don't feel I'm confused at all. The heart of it all is this: saying that an object *implements* a protocol (using the "@interface YourClass <NiftyProtocol>" declaration) is saying that it guarantees to respond to any of a particular set of selectors. The "@protocol NiftyProtocol" declaration (which appears elsewhere, usually in its own header file) specifies what selectors will be responded to. (A protocol's nearest non-Cocoa equivalent would be a Java interface.)
When attached to a method argument, the protocol specification ("id<NiftyProtocol>") says that the method expects to be given an object that responds to the named protocol, presumably because it's going to call one or more of the selectors defined by the protocol.
In this case, the NSMutableCopying protocol defines a method "mutableCopyWithZone:" which any object--of any class--which implements NSMutableCopying will respond to. The NSCopying protocol defines a similar-but-different method "copyWithZone:", which any object implementing NSCopying will respond to. (The NSCopying and NSMutableCopying protocols are completely separate from each other. An object can implement both, either one, or neither.) "Bar:", by attaching the NSMutableCopying protocol name to the argument declaration, says that it requires that its argument respond to "mutableCopyWithZone:". However, "foo:" says that the object passed to it is an object that implements the NSCopying protocol, and so will respond to "copyWithZone:". Nothing is said one way or another about whether it implements NSMutableCopying. Hence, the call to "bar:", which expects an object that responds to "mutableCopyWithZone:" is being handed an object that may or may not respond to it (the comp!
iler has no way to tell), but definitely *does* respond to "copyWithZone:". Since the compiler can't tell that it *will* respond to "mutableCopyWithZone:", it issues a warning to alert you to the potential bug. Had "foo:" been written as
-(void) foo:(id<NSMutableCopying>)t { [self bar:t]; }
there would have been no warnings, because "bar:" would be getting exactly what it wants: an object that responds to "mutableCopyWithZone:".
He wrote:
|Also if you change the declaration of bar as follows:
|
|-(void) bar:(NSObject<NSMutableCopying>*)t
|
|the compiler does NOT complain in all three cases! This means that
|NSObject<NSMutableCopying>* is considered MORE general than
|id<NSMutableCopying>...
The case where "bar:" is declared "-(void) bar:(NSObject<NSMutableCopying>*)t" is a mystery because, by the rules, it shouldn't be acceptable, since "foo:" is still passing it an "id<NSCopying>" object and "bar:" still expects an "id<NSMutableCopying>" object (NSObject doesn't implement either protocol), and the mismatch remains. Since the mismatch remains, there should be a warning. This is the one case that I'd consider a bug, because the compiler *isn't* producing a warning that I'd expect it would.
Glen Fisher
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.