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