[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [objc-improvements] Just remembered something about multiple method

From: Ziemowit Laski
Subject: Re: [objc-improvements] Just remembered something about multiple method signatures...
Date: Sun, 7 Sep 2003 15:09:28 -0700

On Saturday, Sep 6, 2003, at 00:54 US/Pacific, David Ayers wrote:

Ziemowit Laski wrote:

I guess my point is that arbitrarily picking a signature out of a pool
of contenders is fraught with problems, and I still believe that
the IMP fallback is a cleaner solution in this case.  I don't think
doing this breaks (codegen-wise) the counterexample you guys keep
discussing (i.e., where all the candidate methods return NSComparisonResult),
does it?

It doesn't on my architecture and probably not on the G4, but it would on 64 bit archs where small enums (i.e. NSComparisionResult) are not the same size as id (I'm not sure how the G5 handles small enums). In fact it would probably turn into an outright compile time error. I just liked that example because it wasn't constructed. (i.e. NSDate, NSString and NSNumber have different prototypes for '-compare:'.)

But maybe I can offer a more constructed example based on the promotions caused by IMP that shows the issue on all architecures and that given the intensive use of float with NSView subclasses in OPENSTEP derivatives, make it a valid one. I've attached an excerpt of a test we're preparing for contribution.

Class1: -(id)test1Float:(float)f int:(int)i;
Class2: -(Object *)test1Float:(float)f int:(int)i;

In the old case, you could get a warning about the compiler picking the wrong prototype but the results were correct.

In this particular case, the compiler picked a method signature out of a hat that happened to work in that the intended codegen occurred. But just because the "results were correct" in this case does not make the compiler correct. :-( In fact, all you need to do here is add

  Class3: -(void)test1Float:(float)f int:(int)i;

to see just how "incorrect" things can get. :-)

But the new IMP promotion for id typed receivers will promote them to doubles and clobber not only of the float but all following arguments as well

I absolutely agree with you in that using the IMP prototype can also result in "bad" (i.e., unintended) codegen. If you're given a set of competing method signatures, each of them with conflicting codegen requirements, there is absolutely no way you can win here. :-( In the end, the user will simply have to type the receiver more strongly (possibly by casting it at the call site) to pick the intended signature, and I really don't see any other way out of this predicament.

So why did I bother with this IMP thing here?  There are two reasons:
(1) I wanted a consistent failure mode. In your test1Float:int: example above, you see how the compiler may wind up picking a different signature as more and more test1Float:int: methods are added to the mix. The signature that gets picked may happen to "work" in some cases and not work in others (due to the float<->int promotions that both you and I discussed). Of course, the IMP signature may also either work or not work :-); but at least now, it will do so consistently as new incarnations of test1Float:int: are pulled in from who knows where. So choosing IMP preserves consistency of the outcome regardless of the number/kind of conflicting signatures chosen. In addition to being "internally" consistent, choosing IMP here is consistent with what the compiler already does when there are _no_ method signatures available, which leads to the following elegant end-user pronouncement:

Whenever the compiler cannot statically determine the argument types or return type of a method being called, it shall use the
   generic messenger signature (IMP) provided by the runtime system.

Obviously, we could wordsmith the foregoing some more, but as an end-user of the language, I'd love to have a fallback mechanism that is as simple, elegant and consistent as this.

(2) After making its method signature selection, the compiler should be able to proceed as gracefully as possible. These are, after all, warnings rather than errors. However, if a signature with return type 'void' is picked, the compiler will subsequently issue a hard error if the program attempts to use the return value of the message. A milder version of this occurs when the compiler produces a string of warnings about incompatible pointer types of arguments; these warnings are purely a result of the fact that there was a conflict to begin with, and tend to confuse users (as evidenced by bug reports filed against Apple's gcc). So again, the main theme here is consistency of experience: the compiler encountered a situation not to its liking, but should at least resolve it in the same fashion each time.

I think that your suggestion about itteratively comparing the return value and then the arguments before falling back to varadic processing might be a good solution, as long as 'compatible' return values/arguments are "merged" to a general type (such as id/class) before falling back to varadic processing. (The warnings should remain, and if you like, with a flag to turn them off :-) )

Doing this will increase the probability (vs. both the current and the IMP approaches) that the compiler will happen to do "the right thing" (codegen-wise) when encountering conflicts, although of course it won't make it a certainty -- no scheme can do that. The down side is that this scheme lacks the simple elegance (and hence end-user understandability) of the IMP approach. :-(

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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]