[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: |
Mon, 8 Sep 2003 14:28:05 -0700 |
On Monday, Sep 8, 2003, at 03:44 US/Pacific, David Ayers wrote:
Ziemowit Laski wrote:
On Saturday, Sep 6, 2003, at 00:54 US/Pacific, David Ayers wrote:
Given
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 this protoype is not just a conflicting prototype, it's an
outright incompatible prototype, and as I believe Steve Naroff already
suggested, it may be wiser to emit a hard error when prototypes are
not just conflicting but really incompatible rather than second
guessing any fallback prototype.
So now we need compiler logic to distinguish "conflicting" prototypes
from "incompatible" ones. Are you offering to write it (and explain it
to end-users)? :-)
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.
The 'IMP' assumption *will* result in "bad" code generation as soon as
either return type or arguments contain floats. There is absolutly no
ambiguity in that.
Don't follow you here. Why?
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.
Yes! So let's not assume anything in this case, let's make it a hard
error. Assuming 'IMP' will to break more code than picking one did.
Personally, I'd have nothing against a hard error here.
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
Try my example with the old behavior. Change the order of the
declaration. You will see that the old behavior (eventhough possibly
not generating the warning) /always/ generates correct code because
the test1Float:int: were 'compatible' even though they were
conflicting in the exact return type.
It generates code which happens to be correct in this particular case.
You must distinguish correctness from a lucky shot in the dark. :-)
(due to the float<->int promotions that both you and I discussed).
There is no 'float'<->'int' promotion. The varadic processing of
'IMP' promotes all floats to doubles. So the reciever will always get
a double value instead of the expected float, yet it will not fit into
the parameter. The code must break in all cases.
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.
No, the IMP assumption will break /all/ methods that expect float
arguments, but have conflicting prototypes, even if they were
compatible. There is no way for it to do the "right thing" anymore in
the case of float arguments. (In fact there is no way to do the right
thing for any return types that have a different size than id either.)
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.
In the case of conflicting prototypes that are actually incompatible,
as the 'void'/'id' return type example, the hard error is a "Good
Thing"! In fact the /real/ issue is that it could potentially pick
the prototype that declares the 'id' return value, but the message is
actually sent to the object that doesn't return anything. That will
most like result in a runtime error or undefined behavior at least.
In this case the better solution would be a hard compile time error.
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).
Please reconsider the validity of these bug reports. If the compiler
cannot determine the correct prototype to generate code for, the
developer must provide a meaning full cast (and potential runtime
checks using
isKindOfClass:/conformsToProtocol:/methodSignatureForSelector: with
alternative execution paths where each path casts the reciever to the
corresponding type and the compiler can then generate code for the
correct prototype in the corresponding paths.
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. :-(
We are trying to find an elegant way to generate correct code for
ambiguous declarations. The more I think about it, the less I like
even this compromise. I'm starting to lean heavily toward emiting a
hard error where prototypes are not just conflicting but also
incompatible, as this means that the compiler is forced to generate
bad code for some cases. And the case you qoute with conflicting
return types 'id'/'void' would definitely fall into that category.
This behavior should meet your requirement of having a "consistent
failure mode".
The conflicting declarations ('id'/'void' return type), the IMP
assumption tries to generate code for is far more serious that the
conflicting but compatible declarations that were handled correctly by
the previous behavior. We would be exchanging one set of errors for
another. Even worse, the prototype conflicts we are breaking can have
a lot more validity than the new ones we'd be allowing. (see the
covariant/contravariant return type/arguments discussion on
gnustep-discuss)
As I said, the primary virtue of the IMP approach is that it is a
consistent failure mode. But it _is_ a failure, just as the
pick-a-signature-out-of-a-hat approach was. You can and will get bad
codegen with both cases at times. And just because the current
approach may _happen_ to pick the desired result with a higher
probability, that does _not_ make it correct! :-)
Thanks to Chris Hanson (very much appreciated the clairification) I
understand that this issue wasn't as apparent on G5/Dawin as it would
be on other architectures. But none the less these are serious > issues.
Yes, they are -- and neither the existing implementation nor my
proposal (nor any _other_ proposal) can address it. :-(
PS: The "overkill" solution to this is:
a) to generate code for adding something like the
"signatureForSelector:" test
b) generate code for all seen prototypes
c) select the code path at runtime
But I'd definitely would prefer to emit hard errors and require
casting.
Yes, I'd prefer that solution also. Actually, I just conversed with
Steve Naroff who suggested I investigate whether turning this into a
hard error will not be too painful (i.e., if there are not too many
existing selector conflicts in MacOS X sources :-) ). This would apply
to the basic 'id' case, but also to cases like 'id<Foo, Bar>' (where
Foo and Bar have conflicting signatures) or if a category conflicts
with the main interface.
In this case, adding support for 'Class <MyProtocol>' should
accompany that change in behavior.
Yes.
I'm looking into this, but as I'm rather new to compiler hacking it
might take a bit, before I come up with something.
If we develop consensus around the 'hard error' proposal (which I must
admit I like even better than the IMP approach), I'll tackle the
implementation, while you guys can come up with creative test cases. :-)
--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
- [objc-improvements] Just remembered something about multiple method signatures..., Ziemowit Laski, 2003/09/05
- Re: [objc-improvements] Just remembered something about multiple method signatures..., David Ayers, 2003/09/06
- Re: [objc-improvements] Just remembered something about multiple method signatures..., Chris Hanson, 2003/09/07
- Re: [objc-improvements] Just remembered something about multiple method signatures..., Ziemowit Laski, 2003/09/07
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Alexander Malmberg, 2003/09/08
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Ziemowit Laski, 2003/09/08
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Richard Frith-Macdonald, 2003/09/09
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., David Ayers, 2003/09/09
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Ziemowit Laski, 2003/09/09
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Nicola Pero, 2003/09/09
- Re: [objc-improvements] Just remembered something about multiplemethod signatures..., Alexander Malmberg, 2003/09/09