RFC: Enhancing ObjC message lookup in the presence of protocols

Ziemowit Laski zlaski@apple.com
Wed Oct 20 23:03:00 GMT 2004


On 20 Oct 2004, at 1.06, d.ayers@inode.at wrote:

>>
>> 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
> @end
> @interface MyClass

You mean '@interface MyClass: MyRoot', right?  Otherwise your 
subsequent argument
doesn't make sense.

> -method1;
> @end
>
> 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.

But you're messaging an unadorned 'Class' here, so you immediately fall 
back
to the hash table lookup.  This is not related to our discussion.
>
>>>
>>>> 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.
>
> [snip]
>>>
>>> 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.

Your proposal introduces the principle of actually checking where a
given protocol is adopted when messaging an opaque receiver,
and so you should apply this principle consistently.

>
>>>  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;
> @end
> @interface MyClass : MyRoot
> - method2;
> @end
>
> 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.

Yes, but that's because it is messaging an opaque receiver, so it is 
satisfied
with _any_ class method it can find, including instance methods of root 
classes.

> 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;
> @end
>
> 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.

Well, no, I never suggested that all instance methods of protocols 
should be
inserted into the class hash table.

>  But I still think we should do
> better especially since you have now conceeded to collecting the
> information we need.

The reason I agreed to collecting the information is to handle the case 
of
forward-declared protocols.  Come to think of it, though, doing this is
probably not worth the candle (since you should really declare a 
protocol
before using it), so I'll omit it from my patch, at least for now.

I suspect we will not reach an agreement here on the whole "protocols 
adopted
by root classes" business, so I ask that you defer it till another 
patch.

--Zem



More information about the Gcc mailing list