public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: Enhancing ObjC message lookup in the presence of protocols
@ 2004-10-12  6:11 Ziemowit Laski
  2004-10-12 19:17 ` David Ayers
  2004-10-14 17:01 ` David Ayers
  0 siblings, 2 replies; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-12  6:11 UTC (permalink / raw)
  To: gcc List, objc-language; +Cc: David Ayers

This is a fallout from the work that David and I have been doing wrt 
adding 'Class <Proto>' support to
the Objective-C language for the gcc 4.0 compiler (which hopefully will 
go in shortly, BTW).

Given the code

   @protocol Proto
    - method1;
    + method2;
   @end

   @interface Base <Proto>
   @end

   void foo(void) {
     Class cls;
     [cls method1];
   }

the compiler will currently warn:

   proto-ref.m:11: warning: `Class' may not respond to `+method1'
   proto-ref.m:11: warning: (Messages without a matching method signature
   proto-ref.m:11: warning: will be assumed to return `id' and accept
   proto-ref.m:11: warning: `...' as arguments.)

Thing is, the compiler could do better in this case.  Since the 'Base' 
class adopts the
'Proto' protocol, it is reasonable to assume that it will provide a '- 
method1' and
a '+ method2'.  Furthermore, since 'Base' is a root class in our 
example, '- method1'
can be invoked as '+ method1', making the warning above superfluous.

My proposal to attack this problem goes as follows:  Whenever we see an 
interface or
category declaration, we examine the protocols adopted by said 
interface/category and
insert their constituent method signature into the global class or 
instance method
hash tables (as is already being done for methods declared by the 
interface/category
directly).  Also, whenever we are dealing with a root class (or a 
category of a root
class), we add any instance methods from the adopted protocols into the 
global
class hash table (just as instance methods directly declared by root 
classes and
categories already are).

Such a fix should prevent us from issuing many superfluous warnings 
when messaging
objects of type 'id', 'id <Proto>', 'Class' and (now) 'Class <Proto>', 
and will make
things more consistent with what happens when you message a specific 
type
(e.g., 'NSObject *').

What do you think?  Does anyone have any objections to this?  I'll be 
happy to clarify
things if my missive is not understandable. :-)

--Zem
--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-12  6:11 RFC: Enhancing ObjC message lookup in the presence of protocols Ziemowit Laski
@ 2004-10-12 19:17 ` David Ayers
  2004-10-12 21:46   ` Ziemowit Laski
  2004-10-14 17:01 ` David Ayers
  1 sibling, 1 reply; 15+ messages in thread
From: David Ayers @ 2004-10-12 19:17 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc List, objc-language

Ziemowit Laski wrote:
> Given the code
> 
>    @protocol Proto
>     - method1;
>     + method2;
>    @end
> 
>    @interface Base <Proto>
>    @end
> 
[snip]
> 
> My proposal to attack this problem goes as follows: Whenever we see
> an interface or category declaration, we examine the protocols
> adopted by said interface/category and insert their constituent
> method signature into the global class or instance method hash tables
> (as is already being done for methods declared by the 
> interface/category directly). Also, whenever we are dealing with a
> root class (or a category of a root class), we add any instance
> methods from the adopted protocols into the global class hash table
> (just as instance methods directly declared by root classes and 
> categories already are).
> 
> Such a fix should prevent us from issuing many superfluous warnings 
> when messaging objects of type 'id', 'id <Proto>', 'Class' and (now)
> 'Class <Proto>', and will make things more consistent with what
> happens when you message a specific type (e.g., 'NSObject *').
> 
> What do you think? Does anyone have any objections to this? I'll be 
> happy to clarify things if my missive is not understandable. :-)
> 

Your approach is correct but incomplete in an important way.  It is not
just a mater of finding some method in the global class hash table, it
is a matter of finding the appropriate method and using its
corresponding signature for code generation.

As previously pointed out on the gcc-patches@ list: Given common
selector names such as:

@protocol Proto1
- (const char *)name;
- (void)set;
- (int)compare:(id)obj;
- (int)host
@end

@protocol Proto2
- (NSString *)name;
- (NSSet *)set;
- (BOOL)compare:(id)obj;
- (NSString *)host
@end

combined with the fact that currently the instance prototypes of
protocols adopted by root classes are not repeated as their class
counterparts, I find the Class <protocol> support incomplete (to say the
least) if the code below doesn't chose the correct prototype wrt code
generation, independent of whether there are diagnostics emitted due to
the fact that the protocols do not explicitly reiterate the instance
methods as class methods.

@interface MyRoot1 <Proto1>
@end
@interface MyRoot2 <Proto2>
@end

void
foo(void)
{
  Class <MyProto1> cls1 = bar();
  Class <MyProto2> cls2 = baz();

  const char *name1 = [cls1 name];
  NSString *name2 = [cls2 name];

  [cls1 set];
  NSSet *set = [cls2 set];

  int comp1 = [cls1 compare: cls2];
  BOOL comp2 = [cls2 compare: cls1];

  int host1 = [cls1 host];
  NSHost *host2 = [cls2 host];

  ...
}

Cheers,
David

PS: For those that haven't followed this on gcc-patches@, the original
patch does handle this correctly albeit it did it silently.  I've also
posted a modified patch that would emit diagnostics about the fact that
there was no explicit class method in the protocol but would still use
the instance prototype.  I even offered a third version where the
instance prototypes are unconditionally searched as the previous
versions only searched, if the protocol was indeed adopted by some root
class.  I do not understand why using the instance method prototypes for
protocols adopted by root classes seems to be controversial issue.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-12 19:17 ` David Ayers
@ 2004-10-12 21:46   ` Ziemowit Laski
  2004-10-13 14:01     ` David Ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-12 21:46 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc List, objc-language


On 12 Oct 2004, at 9.15, David Ayers wrote:

> @protocol Proto1
> - (const char *)name;
> - (void)set;
> - (int)compare:(id)obj;
> - (int)host
> @end
>
> @protocol Proto2
> - (NSString *)name;
> - (NSSet *)set;
> - (BOOL)compare:(id)obj;
> - (NSString *)host
> @end


If we have

   Class <Proto1, Proto2> cls;
   :
   [cls host];

then, with the patch I just posted to gcc-patches, the compiler
will warn "found `-host' instead of `+host' in protocol(s)", and
then use the `- (int)host' out of Proto1 (i.e., as if we were
messaging 'id <Proto1, Proto2>').

Arguably, both the 'id <Proto1, Proto2>' and 'Class <Proto1, Proto2>'
cases should result in an additional warning about multiple '-host' 
methods being
found.  This can be addressed by a separate patch.  (A more general
problem is when messaging, e.g., 'NSObject <Proto1, Proto2>', where a 
method
declared by NSObject itself clashes with what Proto1 and/or Proto2 
provide.)


> @interface MyRoot1 <Proto1>
> @end
> @interface MyRoot2 <Proto2>
> @end
>
> void
> foo(void)
> {
>   Class <MyProto1> cls1 = bar();
>   Class <MyProto2> cls2 = baz();
>
>   const char *name1 = [cls1 name];
>   NSString *name2 = [cls2 name];
>
>   [cls1 set];
>   NSSet *set = [cls2 set];
>
>   int comp1 = [cls1 compare: cls2];
>   BOOL comp2 = [cls2 compare: cls1];
>
>   int host1 = [cls1 host];
>   NSHost *host2 = [cls2 host];
>
>   ...
> }

I'll double-check, but I believe my current patch will perform correct 
method selections for this test case.
I think I'll collect the code fragments in this e-mail and make a 
class-protocol-2.m out of it. :-)

--Zem
--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-12 21:46   ` Ziemowit Laski
@ 2004-10-13 14:01     ` David Ayers
  0 siblings, 0 replies; 15+ messages in thread
From: David Ayers @ 2004-10-13 14:01 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc List, objc-language

Ziemowit Laski wrote:

> On 12 Oct 2004, at 9.15, David Ayers wrote:
> 
> 
>>@protocol Proto1
>>- (const char *)name;
>>- (void)set;
>>- (int)compare:(id)obj;
>>- (int)host
>>@end
>>
>>@protocol Proto2
>>- (NSString *)name;
>>- (NSSet *)set;
>>- (BOOL)compare:(id)obj;
>>- (NSString *)host
>>@end
> 
> 
> 
> If we have
> 
>    Class <Proto1, Proto2> cls;

This is not the case I'm worried about.  We had agreed to look at the
case of conflicting prototypes later.  Anything is fine be currently.

> I'll double-check, but I believe my current patch will perform correct 
> method selections for this test case.
> I think I'll collect the code fragments in this e-mail and make a 
> class-protocol-2.m out of it. :-)

Indeed, I'm sorry I misinterpreted your previous example above.  I now
had time to test the patch a bit (I still hope to take a closer look
though.) It is indeed awkward though that (returning to your example):

@protocol Proto
- method1;
+ method2;
@end

Class <Proto1> clsP1;
Class cls;

[clsP1 method1];
/* Will select the correct prototype from the protocol, but ... */
[cls method1];
/* .. won't find any prototype at all! */

because the instance methods for protocols adopted by root classes are
not inserted into the global hash table.

This strangeness becomes obvious when looking at the NSObject protocol
and compare it to the NSObject interface declaration.

@protocol NSObject

- (BOOL)isEqual:(id)object;
- (unsigned)hash;

*- (Class)superclass;
*- (Class)class;
- (id)self;
- (NSZone *)zone;

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1
withObject:(id)object2;

- (BOOL)isProxy;

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;

- (BOOL)respondsToSelector:(SEL)aSelector;

- (id)retain;
- (oneway void)release;
- (id)autorelease;
- (unsigned)retainCount;

*- (NSString *)description;

@end

where only the selectors marked with (*) are repeated as class method
declarations of NSObject proper and therefor become part of the class
hash table.

But I can concede to this being viewed as a separate issue if we do not
introduce the concept of "protocols adopted by root classes".  Yet I'd
would be nice to understand your reservations against this concept
better.  In fact it would allow us to do better at selecting the correct
prototype in the presence of conflicting prototypes later.  But anyway,
that isn't the issue I was worried about.

Cheers,
David

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-12  6:11 RFC: Enhancing ObjC message lookup in the presence of protocols Ziemowit Laski
  2004-10-12 19:17 ` David Ayers
@ 2004-10-14 17:01 ` David Ayers
  2004-10-15  3:32   ` Ziemowit Laski
  1 sibling, 1 reply; 15+ messages in thread
From: David Ayers @ 2004-10-14 17:01 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc List, objc-language

Ziemowit Laski wrote:

> My proposal to attack this problem goes as follows: Whenever we see
> an interface or category declaration, we examine the protocols
> adopted by said interface/category and insert their constituent
> method signature into the global class or instance method hash tables
> (as is already being done for methods declared by the 
> interface/category directly). Also, whenever we are dealing with a
> root class (or a category of a root class), we add any instance
> methods from the adopted protocols into the global class hash table
> (just as instance methods directly declared by root classes and 
> categories already are).

Isn't this exactly what my patch did?  The main reason I had to mark the
protocols adopted by root is for the case of forward declared protocols
adopted by root classes in which case we haven't seen the methods yet.

> Such a fix should prevent us from issuing many superfluous warnings 
> when messaging objects of type 'id', 'id <Proto>', 'Class' and (now)
> 'Class <Proto>', and will make things more consistent with what
> happens when you message a specific type (e.g., 'NSObject *').

Not only do we prevent the superfluous warnings, we also use the correct
prototypes for code generation.

Cheers,
David

PS: Will you also send a mail concerning the semantic changes to
objc_comptypes that your implementation has introduced?  I do agree with
some of them, but I don't think that they should be part of this patch.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-14 17:01 ` David Ayers
@ 2004-10-15  3:32   ` Ziemowit Laski
  2004-10-15 19:18     ` David Ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-15  3:32 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc List, objc-language


On 14 Oct 2004, at 7.34, David Ayers wrote:

>> My proposal to attack this problem goes as follows: Whenever we see
>> an interface or category declaration, we examine the protocols
>> adopted by said interface/category and insert their constituent
>> method signature into the global class or instance method hash tables
>> (as is already being done for methods declared by the
>> interface/category directly). Also, whenever we are dealing with a
>> root class (or a category of a root class), we add any instance
>> methods from the adopted protocols into the global class hash table
>> (just as instance methods directly declared by root classes and
>> categories already are).
>
> Isn't this exactly what my patch did?  The main reason I had to mark 
> the
> protocols adopted by root is for the case of forward declared protocols
> adopted by root classes in which case we haven't seen the methods yet.

Your patch did more than that, I think, but overall you do raise a good
point.  Either we should handle forward-declared protocols as you 
suggest,
or else I should drop the second part of my proposal.  At any rate,
let's defer this to the next patch, and separate it from adding
'Class <Proto>' to the compiler in the first place.

> PS: Will you also send a mail concerning the semantic changes to
> objc_comptypes that your implementation has introduced?  I do agree 
> with
> some of them, but I don't think that they should be part of this patch.

Which ones do you mean?  I did notice that objc_comptypes is buggy in
some cases (marked as FIXMEs in class-protocol-1.m), but I resisted
mission creep in that case, since these bugs can be fixed as part of
a future objc_comptypes rewrite.

Aside from this, do you see any other problems with my current patch?
I know it still doesn't do everything you want, and you do raise
a good point about forward-declared protocols, but we should separate
concerns here and attack remaining problems with a separate patch.

Thanks,

--Zem

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-15  3:32   ` Ziemowit Laski
@ 2004-10-15 19:18     ` David Ayers
  2004-10-18  4:13       ` Ziemowit Laski
  0 siblings, 1 reply; 15+ messages in thread
From: David Ayers @ 2004-10-15 19:18 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc List, objc-language

Ziemowit Laski wrote:

> Your patch did more than that, I think, but overall you do raise a good
> point.  Either we should handle forward-declared protocols as you 
> suggest,
> or else I should drop the second part of my proposal.  At any rate,
> let's defer this to the next patch, and separate it from adding
> 'Class <Proto>' to the compiler in the first place.
> 

Well if you follow that thought through just a tad more then you'd
return to the original functionality I posted...

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.  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!
It's really not that big of step and makes the whole search consistent.

> 
>> PS: Will you also send a mail concerning the semantic changes to 
>> objc_comptypes that your implementation has introduced? I do agree 
>> with some of them, but I don't think that they should be part of
>> this patch.
> 
> 
> Which ones do you mean?  I did notice that objc_comptypes is buggy in
> some cases (marked as FIXMEs in class-protocol-1.m), but I resisted
> mission creep in that case, since these bugs can be fixed as part of
> a future objc_comptypes rewrite.
> 

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
(from comp-types-1.m):
  /* Assigning to an 'id' variable should never
     generate a warning.  */
  obj = obj_p;  /* Ok  */
  obj = obj_c;  /* Ok  */
  obj = obj_cp; /* Ok  */
  obj = obj_C;  /* Ok  */

...
  /* Any comparison involving an 'id' must be without warnings.  */
  if (obj == obj_p) ;  /* Ok  */ /*Bogus warning here in 2.95.4*/
  if (obj_p == obj) ;  /* Ok  */
  if (obj == obj_c) ;  /* Ok  */
  if (obj_c == obj) ;  /* Ok  */
  if (obj == obj_cp) ; /* Ok  */
  if (obj_cp == obj) ; /* Ok  */
  if (obj == obj_C) ;  /* Ok  */
  if (obj_C == obj) ;  /* Ok  */


> Aside from this, do you see any other problems with my current patch?

Other than the objc_comptypes issue I just mentioned (and that I
personally consider the 'Class <protocol>' support incomplete without
the infamous "root protocol" handling described above) I have found none
worth mentioning. :-).

Cheers,
David

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-15 19:18     ` David Ayers
@ 2004-10-18  4:13       ` Ziemowit Laski
  2004-10-18 16:31         ` David Ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-18  4:13 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc List, objc-language

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-18  4:13       ` Ziemowit Laski
@ 2004-10-18 16:31         ` David Ayers
  2004-10-19 15:15           ` Ziemowit Laski
  0 siblings, 1 reply; 15+ messages in thread
From: David Ayers @ 2004-10-18 16:31 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc List, objc-language

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-18 16:31         ` David Ayers
@ 2004-10-19 15:15           ` Ziemowit Laski
  2004-10-19 23:24             ` d.ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-19 15:15 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc List, objc-language


On 18 Oct 2004, at 5.29, David Ayers wrote:

> 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 */
>

I guess you meant '/* not implemented by protocol(s) */', right?  If we 
were _never_ to look at instance methods in these cases, then 'not 
implemented by protocol(s)' would be right.  However, since we agreed 
that we should look at instance methods in protocols should class 
method lookup fail, I do not think we should attempt to guess what type 
of object 'clsP2' is actually pointing at.

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.

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 */


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

Yes, it _should_ be ambiguous, since you will have two conflicting 
method signatures, just as with

   id obj;
   [obj name];

which is also ambiguous.

I guess my overall point is: 'Class' and 'id' may hold an object of 
_any_ ObjC type, and not just types that you happen to have seen in 
your own translation unit thus far.  Protocol lists attached to 'Class' 
or 'id' give you an opportunity to look through the protocols first, 
but again without regard to what the underlying object type might or 
might not be.

--Zem

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-19 15:15           ` Ziemowit Laski
@ 2004-10-19 23:24             ` d.ayers
  2004-10-20  9:59               ` Ziemowit Laski
  0 siblings, 1 reply; 15+ messages in thread
From: d.ayers @ 2004-10-19 23:24 UTC (permalink / raw)
  To: zlaski; +Cc: gcc, objc-language

>
> On 18 Oct 2004, at 5.29, David Ayers wrote:
>
>> 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 */
>>
>
> I guess you meant '/* not implemented by protocol(s) */', right?

Indeed, thanks.

> If we
> were _never_ to look at instance methods in these cases, then 'not
> implemented by protocol(s)' would be right.  However, since we agreed
> that we should look at instance methods in protocols should class
> method lookup fail, I do not think we should attempt to guess what type
> of object 'clsP2' is actually pointing at.
>
> 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.

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

>
>> 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.
>
> Yes, it _should_ be ambiguous, since you will have two conflicting
> method signatures, just as with
>
>    id obj;
>    [obj name];
>
> which is also ambiguous.

I maintain that [cls name] in unambiguous, as we know of only one class
which implements +name.  And that is MyRootClass as it adopt my Proto1,
where as Proto2 is adopted merely by a non-root class.  It's undisputed
that [obj name] is ambigious.

> I guess my overall point is: 'Class' and 'id' may hold an object of
> _any_ ObjC type, and not just types that you happen to have seen in
> your own translation unit thus far.  Protocol lists attached to 'Class'
> or 'id' give you an opportunity to look through the protocols first,
> but again without regard to what the underlying object type might or
> might not be.

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.  I think you're implying that "we may have not seen the
header that does", and therefor we shouldn't be using that information.  I
hold against that, that we "never" know what other classes my implement. 
Take the example:

@interface MyRoot
@end
@interface MyClass : MyRoot
-method;
@end

void func2 (id obj, Class cls)
{
  [obj method];/* OK */
  [cls method]; /* no method found (haven't verfied the exact warning)*/
}

@interface MyRoot (extension)
-method;
@end

void func2 (id obj, Class cls)
{
  [obj method];/* OK */
  [cls method]; /* OK */
}

So, yes, you must provide all relevant declarations for correct
diagnostics (and code generation).  But I don't think we should ignoring
the information we /do/ have.

I guess what's bothering you, is that when you use
Class <Proto2> clsP2;
and you know there are certain root classes that adopt this protocol and
you expect the object to be one of them or even test with
respondsToSelector: before dispatching thje instance method, ... that you
would have to #include/#import the header of one of those root class so
that messages sent to clsP2 would use the instance methods, if we
constrained them as I described.  OTOH, if we use an instance method on a
class (Class cls) we would also have to #include/#import a root class
which declares that instance method for the compiler to produce the
correct disgonstics and select the correct prototype.  I think the same
logic applies here.

Cheers,
David



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-19 23:24             ` d.ayers
@ 2004-10-20  9:59               ` Ziemowit Laski
  2004-10-20 12:49                 ` d.ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-20  9:59 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc, objc-language


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?
>
>> 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? :-)

>
>>
>>> 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.
>>
>> Yes, it _should_ be ambiguous, since you will have two conflicting
>> method signatures, just as with
>>
>>    id obj;
>>    [obj name];
>>
>> which is also ambiguous.
>
> I maintain that [cls name] in unambiguous, as we know of only one class
> which implements +name.  And that is MyRootClass as it adopt my Proto1,
> where as Proto2 is adopted merely by a non-root class.  It's undisputed
> that [obj name] is ambigious.
>
>> I guess my overall point is: 'Class' and 'id' may hold an object of
>> _any_ ObjC type, and not just types that you happen to have seen in
>> your own translation unit thus far.  Protocol lists attached to 
>> 'Class'
>> or 'id' give you an opportunity to look through the protocols first,
>> but again without regard to what the underlying object type might or
>> might not be.
>
> 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?

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

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

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.

--Zem

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-20  9:59               ` Ziemowit Laski
@ 2004-10-20 12:49                 ` d.ayers
  2004-10-20 23:03                   ` Ziemowit Laski
  0 siblings, 1 reply; 15+ messages in thread
From: d.ayers @ 2004-10-20 12:49 UTC (permalink / raw)
  To: zlaski; +Cc: gcc, objc-language

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

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

>>  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. 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.  But I still think we should do
better especially since you have now conceeded to collecting the
information we need.

Cheers,
David



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-20 12:49                 ` d.ayers
@ 2004-10-20 23:03                   ` Ziemowit Laski
  2004-10-21 16:28                     ` David Ayers
  0 siblings, 1 reply; 15+ messages in thread
From: Ziemowit Laski @ 2004-10-20 23:03 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc, objc-language


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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: RFC: Enhancing ObjC message lookup in the presence of protocols
  2004-10-20 23:03                   ` Ziemowit Laski
@ 2004-10-21 16:28                     ` David Ayers
  0 siblings, 0 replies; 15+ messages in thread
From: David Ayers @ 2004-10-21 16:28 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc, objc-language

Ziemowit Laski wrote:

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

Yes, excuse me (again).

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

It was meant as an analogy.  All I was trying to say with that example
is that the compiler always only knows what it has seen so far and acts
upon that.  This was in response to "Does that mean that _no_ root class
in your program adopts it...".  No it doesn't mean that, yet it does
mean the compiler should be free to act upon the information it has seen
so fat.  My point was it should suffice that the compiler knows that at
least one root class adopts it.  Once it knows that, I feel it's
legitimate to assume that we should use the prototype of the instance
method of the, before using the global class hash table.  We had earlier
agreed on /always/ using the instance method.  I'm proposing to use the
information to constrain the drop back.

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

My proposal intends to take into account the special semantics of
instance methods of root classes with respect to protocols adopted by
such root classes.  This indeed includes adorning the protocol dependent
on where its used and then using that information when that protocol is
used with a protocol qualified opaque 'Class' reference.  There are no
special semantics for the opaque 'id' case where this 'principle' could
be applied 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.
>

The point was...

> 
>> 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 */
>>}
>>

... that the compiler only know what it knows so far.  And because it
hasn't seen a root class adopting the protocol yet would be sufficient
to constrain the fallback lookup into the /instance/ methods of the
protocol and rely on the global /class/ hash table instead.

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

Please don't.  It may not be relevant in practice as I can't think of a
good reason why anyone should merely forward declare a protocol, have a
class adopt it and then declare it, but you never know how people write
their headers and what circumstances result in defining the order they
are included.

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

Possibly.  Maybe we could find some time to talk this over on the phone
(I've tried a few times but somehow it's always been the wrong time).
For know, please go ahead with marking the protocols and only populating
the class hash with the instance methods when a root class adopts it and
leave the fallback lookup of the instance methods of protocols
unconditionally.

Cheers,
David

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2004-10-21 14:33 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-10-12  6:11 RFC: Enhancing ObjC message lookup in the presence of protocols Ziemowit Laski
2004-10-12 19:17 ` David Ayers
2004-10-12 21:46   ` Ziemowit Laski
2004-10-13 14:01     ` David Ayers
2004-10-14 17:01 ` David Ayers
2004-10-15  3:32   ` Ziemowit Laski
2004-10-15 19:18     ` David Ayers
2004-10-18  4:13       ` Ziemowit Laski
2004-10-18 16:31         ` David Ayers
2004-10-19 15:15           ` Ziemowit Laski
2004-10-19 23:24             ` d.ayers
2004-10-20  9:59               ` Ziemowit Laski
2004-10-20 12:49                 ` d.ayers
2004-10-20 23:03                   ` Ziemowit Laski
2004-10-21 16:28                     ` David Ayers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).