This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: RFC: Enhancing ObjC message lookup in the presence of protocols
On 15 Oct 2004, at 10.00, David Ayers wrote:
We don't artificially constrain marking forward declared protocols, but
mark all protocols adopted by root classes. And insure the class hash
is filled with the corresponding methods. Then we also insure this is
done for inherited protocols of root protocols.
I'm with you as far as putting these in the hash table. I'm also
willing
to go along with specially marking protocols that are adopted (directly
or indirectly) by root classes, but not yet defined, so that we may
inject
their methods into said hash table later. The reason I say "go along"
is
that one could plausibly view a forward-declared (but not yet defined)
protocol as _intentionally_ opaque.
So now we have the
"protocols adopted by root classes" marked, and we can use that
information during method lookup, do constrain the 'Class <Proto>'
lookup only to those marked protocols. And now we're not only
potentially a tad bit faster but also more correct in the sense that we
reduce the potential of finding bogus cases of conflicting protocols!
And this is where you lose me. :-( If you have
@protocol Proto1
- (const char *) message;
+ (int) value;
@end
@protocol Proto2
- (NSString *) message;
+ (float) value;
@end
id <Proto1, Proto2> idP1P2;
Class <Proto1, Proto2> clsP1P2;
then the following four message sends below are _all_ inherently
ambiguous:
[idP1P2 message];
[idP1P2 value];
[clsP1P2 message];
[clsP1P2 value];
The reason they are inherently ambiguous is because the Proto1 and
Proto2
make mutually inconsistent claims about method signatures, and it is
not really
possible to have a class that satisfies both protocols! In other
words, there
is no such thing as 'bogus cases of conflicting protocols' -- all such
cases
are real, and indicate an inconsistent set of assumptions about the
'idP1P2' and
'clsP1P2' objects above.
Your proposal is to leverage additional information, such as
@interface Root <Proto1>
@end
to infer that '[clsP1P2 message]' refers to '- (const char *) message'
(BTW,
would you make the same argument wrt '[idP1P2 message]', thereby
changing
existing behavior?). However, just because you haven't seen a
@interface Root2 <Proto2>
@end
or, for that matter,
@implementation Root3
- (NSString *)message { .... }
@end
does not mean that they do not exist in some translation unit making up
your
program. Far from making your message dispatch 'more correct', you are
lulling
yourself into a false sense of correctness by selectively ignoring
conflicts
that the ObjC type system (FWIW :-) ) shows you are there.
It's really not that big of step and makes the whole search consistent.
It is not only inconsistent as far as lookup of class vs. instance
methods
is concerned, it will also be inconsistent wrt lookup of instance
methods
for the 'id <Proto1, Proto2>' case. Do you also only want to search
Proto1
in that case, on the grounds that the Root class adopts it?
Actually I'm only concerned about:
(diff between my version and your version of class-protocol-1.m):
{ /* Class <protocol>, id */
- obj == clsP1;
- clsP1 == obj;
+ obj == clsP1; /* { dg-warning "lacks a cast" } */
+ clsP1 == obj; /* { dg-warning "lacks a cast" } */
{ /* Class <protocol>, id */
- obj = clsP1;
- clsP1 = obj;
+ obj = clsP1; /* { dg-warning "incompatible" } */
+ clsP1 = obj; /* { dg-warning "incompatible" } */
As I believe an unadorned 'id' should always be legal
Oooh, you are absolutely correct here; my bad. I'll fix it.
Thanks for your patience,
--Zem