RFC: Enhancing ObjC message lookup in the presence of protocols

David Ayers d.ayers@inode.at
Mon Oct 18 16:31:00 GMT 2004


Ziemowit Laski wrote:
> On 15 Oct 2004, at 10.00, David Ayers wrote:
> 
> 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.
> 

Well if it is indeed /only/ forward-declared, then it will remain 
opaque.  Yet if it is later declared (i.e. before the methods are used) 
I cannot see a reason why not to use the prototypes for code generation.


>>   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];
> 

Absolutely agreed!

> 
> 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.

This is not the case I'm worried about and not the case I'm trying to 
deal with.  As you very well described, it is ambiguous and I view it as 
undefined behavior if a Class / object adopts protocols with 
incompatible signatures.

Let's try this example

@protocol MyProto1
- (const char *)name;
@end

@protocol MyProto2
- (NSString *)name;
@end

@interface MyRootClass <MyProto1>
@end

@interface OtherRootClass
@end

@interface MyClass : OtherRootClass <MyProto2>
@end

In this case <MyProto2> is not a protocol declared by a root class. 
Therefor we should not be falling back to the instance methods in the 
case of:

Class <Proto2> clsP2;
[clsP2 name]; /* may not respond */

and the case:

Class cls;
[cls name]; /* OK */

should not be ambiguous as there is only one prototype declared by 
MyProto1 which should be in the class hash table.

I am aware that in the first case above the compiler does fall back to 
/use/ the prototype from the class hash table of the second case, but 
the user has been warned, so that's fine.  We do avoid using the 
instance signatures of MyProto2 incorrectly.

I'm less worried about the cases you described, where the fact that 
MyProto2 is first used as a non-root protocol and later found to be 
adopted by a root class.  I think we should only use the information 
that we've seen up to the point where we need it.

Cheers,
David



More information about the Gcc mailing list