Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!cs.utexas.edu!milano!cadillac!sunburn!dsouza From: dsouza@mcc.com Newsgroups: comp.lang.c++ Subject: OVERLOADING + CLASS DERIVATION = PROBLEM Message-ID: <3378@cadillac.CAD.MCC.COM> Date: 18 Oct 89 22:58:57 GMT Sender: news@cadillac.CAD.MCC.COM Reply-To: dsouza@mcc.com Organization: MCC VLSI-CAD Program, Austin, TX Lines: 102 When resolving an overloaded function, based on Lippman, p 160: "Closeness of type is not considered." it seems that the number of type conversions required for a match is not considered in resolving a call. I understand this as a safety feature with silent built-in conversions. However, I dont think it fits in well with class derivation, as the philosophy and purpose of automatic conversions in a type hierarchy is QUITE different. Maybe the 2 kinds of conversions should be distinguished? I hear "aargh!"s, but think about it for a minute. Here is an example: Consider: class X; class A {}; class B : public A {}; class C : public B {}; // C subTypeOf B subTypeOf A // now for some overloading: // I've added the X argument only so you wont say: Use A::foo member function void foo (X, A) { ... } // [foo1] fine: if I did not define foo(A,B), // this WOULD apply to (X,B) and (X,C) void foo (X, B) { ... } // [foo2] fine: SHOULDN'T THIS APPLY TO AN (X, C) pair? main () { A a; B b; C c; X x; foo(x,a); // FINE: Perfect match with [foo1] foo(x,b); // FINE: Perfect match with [foo2] overrides 1 conversion match with [foo1] foo(x,c); // ERROR: 2 matches: 1 conversion -> [foo2], 2 conversions -> [foo1] } I'd like to make the following argument against this behaviour, based on some of the professed goals of overloaded functions and inheritance (and my interpretations of them :-) 1. To dispatch to different functions based on the static (dynamic) type of the first argument use non-virtual (virtual) member functions. For dynamic dispatch, the types have to be related by class derivation. [1a] One can view this as associating the specialized function directly with what triggered the specialization: i.e. the new class. [1b] This permits logically keeping the function definitions with the class definition, the lexical convenience of using the same function name for "similar" functions, and for virtuals, further eliminates nasty looking run-time tag-based switch statements. 2. To dispatch to different functions based on the static type of class arguments (or non-class args) other than the first, use overloaded functions. e.g. you may have different implementations of SHOW_OBJ_IN_VIEW (OBJ,VIEW) for different class pairs: , , etc. [2a] One can view this as associating the different implementations with what triggered the difference: i.e. COMBINATIONS of argument classes, or those arguments which are discriminnated on by the compiler to resolve calls. [2b] This permits the lexical convenience of using the same function name for "similar meaning" functions with differing implementations. 3. One of the PURPOSES of class derivation (public derivation) is to extend/specialize the behaviour of functions for the BASE class in the DERIVED class. [3a] One can view this as associating the specialized function directly with what triggered the specialization: i.e. the new class. [3b] The inheritance permits most behaviour to be automatically defined for the new class, and the specialized behaviour is associated where is logically belongs. Therefore: as a logical extension of these same principles: If CLASS DERIVATION allow behaviour to be inherited by DEFAULT, and OVERLOADED FUNCTIONS allow functions to discriminate (specialize) on the types of more than one argument (ok, so its limited to compile time) : --> Why not allow OVERLOADED functions to (effectively) do INHERITANCE, by discriminating on the class derivation hierarchy? I know that by ARTIFICIALLY breaking up the overloaded function "foo" into pieces, and putting those pieces into MEMBER FUNCTIONS, I can fake this, but this would violate several of the principles [1a], [1b], ... [3b] above. Ditto for casts: What I'm suggesting is perfectly type safe and just refines ambiguity resolution. Furthermore, overloaded functions (multiple discriminants) and inheritance (automatic conversions), in combination seem designed for just this. COMPATIBILITY NOTE: Extending overloaded function resolution to consider "Closeness" of type match should not break any working code: it will simply successfully resolve some calls which would previously be flagged as ambiguous. Cheers. Desmond D'Souza Desmond D'Souza, MCC CAD Program | ARPA: dsouza@mcc.com | Phone: [512] 338-3324 Box 200195, Austin, TX 78720 | UUCP: {uunet,harvard,gatech,pyramid}!cs.utexas.edu!milano!cadillac!dsouza