RFC: Enhancing ObjC message lookup in the presence of protocols

d.ayers@inode.at d.ayers@inode.at
Wed Oct 20 12:49:00 GMT 2004

> On 19 Oct 2004, at 12.56, d.ayers@inode.at wrote:
>>> So, '[clsP2 name]' above should result in the compiler telling you
>>> 'found -name instead of +name in protocol(s)', and then using '-
>>> (NSString *)name' out of Proto2.
>> We are not guessing what kind of object clsP2 contains.  We would be
>> using
>> the information we do have about Proto2 to constrain the fallback to
>> the
>> instance method search.
> But the most you can say about Proto2 in your example is that none of
> the
> root classes that you have seen adopt it.  Does that mean that _no_ root
> class in your program adopts it and/or provides the methods that Proto2
> requires?

As far as the compiler is concerned, yes!  Just like:

@interface MyRoot
@interface MyClass

means that no root class implements method1.  If non is seen by the
compiler then it should  warn if it sees:

void func(Class cls)
  [cls method1];  /* no method found */

as it correctly does.  It doesn't make assumptions about whether there
could be some other root class that may implement method1 that it hasn't
seen yet.  But once it does, it will not warn.

>>> Alternatively, if you know what type of object 'clsP2' was pointing
>>> at,
>>> then you should type it appropriately, e.g.,
>>>    SomeClass <Proto2> *clsP2;
>>>    [clsP2 name];  /* this will issue a more precise diagnostic */
>> Here you have an object, not a class anymore, but that is a different
>> issue.
> True, true...  I guess perhaps we should think of notation to denote
> class objects
> of a specific type? :-)

Like I said, this is a different issue.

>> What I'm trying to show is that "to look through protocols" in the
>> case of
>> 'Class <protocol>' should heed the information we have about the
>> protocols
>> when taking into account the sematics of instance methods of root
>> classes.
>> You initially disliked the idea of "protocols adopted by root
>> classes". In the absence of this infomormation, I conceeded to at
>> least add the instance methods search for all protocols, eventhough
>> this approach  will
>> induce false positives as described above.  You implicitly affirmed in
>> this thread that we should adorn protocols with the status "adopted by
>> root classes" to handle the global class cache correctly.  Now I'm
>> saying,
>> if we have the infomation with the protocol, why not also use it for
>> lookup of protocol qualified classes to constrain the instance method
>> search for adorned protocols.
>> We "know" that no class has adopted the protocol as a root protocol if
>> it's not adorned.
> But do you know that none of the root classes (even in your own
> translation
> unit, let alone others) nevertheless provide the method you're looking
> for?

All the compiler knows and should know, is what it has seen (see example
above).  If it sees more applicable prototypes then it should (and does)
take them into account.

> For your approach to be fully consistent, shouldn't you _always_ check
> which protocols are adopted where?  For example, given
>    id <Foo, Bar, Baz> obj;
>    [obj mess];
> shouldn't you check whether Foo, Bar and Baz have been adopted by some
> class somewhere, root or non-root?  I really don't think we want to go
> down this path, not least because this would entail changing the
> long-established semantics of message dispatch. :-(

Why do you think I'm inferring that there should be some root/non-root
handling here?  I definitely didn't mean to.  'obj' is an object, and it
should only concern itself with instance methods.  There are no implicit
semantics with respect to root classes or class methods.

>>  I think you're implying that "we may have not seen the
>> header that does", and therefor we shouldn't be using that
>> information.
> Not when we're messaging an opaque receiver such as 'Class' or 'id'.
> Aside from
> collecting encountered method signatures in our global hash tables, we
> shouldn't
> make any assumptions about the type of the receiver (and, therefore,
> whether the
> root class of the receiver's hierarchy adopts a given protocol or not).

I am not making assumptions about the 'Class' other than consistently
transfering the existing assumptions that we make in analogous cases:

@interace MyRoot
- method1;
@interface MyClass : MyRoot
- method2;

void func1(Class cls)
  [cls method1]; /* OK */
  [cls method2]; /* No method found */

If the compiler sees that a root class declares method1 (an instance
method) it also inserts it into the class hash list, as it /knows/ that
some root class implements it. If it doesn't see it in a root class (ie.
method2) then it warns.  It is irrelevant whether later in the translation
unit it sees:

@interface MyRoot (extensions)
- method2;

which include method2 in the class hash list and from then on will not
warn about that message being sent to 'Class cls' anymore:

void func2(Class cls)
  [cls method1]; /* OK */
  [cls method2]; /* OK */

> Anyway, I think we're sort of circling the drain here. :-)  I'll update
> my patch
> to fix the type comparison snafus you found.  I think that I'll also
> populate
> the hash tables with methods from protocols, including handling of
> forward-declared
> protocols adopted by root classes.

Populating the class hash with instance methods of protocols unconstrained
is better than not populating them at all.  But I still think we should do
better especially since you have now conceeded to collecting the
information we need.


More information about the Gcc mailing list