stephens@motcid.UUCP (Kurt Stephens) (08/31/90)
Why isn't the return datum type used in the construction of a function signature? Would it be helpful to have overloaded with the same argument signatures but different return types? For example: 1 class Foo; 2 class Bar; 3 class Tickle { // couldn't think of a better name ;^) 4 Foo f; 5 Bar b; 6 public: 7 Foo Get( void ) { return f; } // note the different 8 Bar Get( void ) { return b; } // return types 9 }; 10 11 main() { 12 Foo f; 13 Bar b; 14 Tickle t; 15 16 f = t.Get(); // would call Foo Tickle::Get( void ) 17 b = t.Get(); // would call Bar Tickle::Get( void ) 19 } Is this impossible because the call to Get() can only be disambiguated by examining the surrounding context? Could, the assignment (in line 16) be interpreted as "assign Foo f with the value of Foo Tickle T::Get()" obviously? If this is possible what would happen if there were cast operators between classes Foo and/or Bar? Example: Foo::operator Bar ( void ) { /* something */ } Bar::operator Foo ( void ) { /* something */ } Would this make the expression "f = t.Get();" ambigous again? I don't really know if this is feasable or useful; I'm just asking. (i.e. Be gentle with me.) -- Kurt A. Stephens ...!uunet!motcid!stephens
mat@mole-end.UUCP (Mark A Terribile) (09/03/90)
In article <4335@celery34.UUCP>, stephens@motcid.UUCP (Kurt Stephens) writes: > Why isn't the return datum type used in the construction of > a function signature? Would it be helpful to have overloaded > with the same argument signatures but different return types? . . . > Is this impossible because the call to Get() can only > be disambiguated by examining the surrounding context? You've hit upon it, more or less. In many languages (Ada included) the context can be used to help in disambiguation. C's very flexible expression syntax and semantics are such that, were C++ to allow such disambiguation, the rules that would have to be applied would prevent `ordinary' C things from working correctly. For example, if you have a pair of overloads disambiguated only by their return values (say an int s() and an X s() ) and you call the function at the top level of an expression statement, i.e. as { s(); } how do you disambiguate? Even if you argue that you are converting the return values to void , on the basis of what could you prefer one conversion to void over another? In other languages, expressions are tightly constrained things; in C and C++, they are the world. There is an almost LISPis quality about them, and that means that there are things you cannot do. It should be noted that it took several months and a number of papers in various journals before the computing community solidly established that there is a usable algorithm for Ada-style disambiguation. It may take four passes over the expression tree before everything is fully disambiguated. -- (This man's opinions are his own.) From mole-end Mark Terribile
jangr@microsoft.UUCP (Jan GRAY) (09/06/90)
In article <431@mole-end.UUCP> mat@mole-end.UUCP (Mark A Terribile) writes: >You've hit upon it, more or less. In many languages (Ada included) >the context can be used to help in disambiguation. C's very flexible >expression syntax and semantics are such that, were C++ to allow such >disambiguation, the rules that would have to be applied would prevent >`ordinary' C things from working correctly. Unfortunately, C++ does occasionally use context to disambiguate, however it doesn't affect the behaviour of "'ordinary' C things". Consider these examples: - Address of overloaded function. void f(); void f(int); void (*pf1)() = &f; void (*pf2)(int) = &f; Here the value of the expression '&f' depends upon the context it appears in. - Multiple conversion functions. class IPI { public: operator int(); operator int*(); }; void fi(int); void fpi(int*); void fipi(IPI); int* foo() { IPI ipi; IPI ipi2 = ipi; // use ipi as an ipi object int i = ipi; // int i = ipi.operator int(); int* pi = ipi; // int *pi = ipi.operator int*(); +ipi; // +(ipi.operator int()); *ipi; // *(ipi.operator int*()); fi(ipi); // fi(ipi.operator int()); fpi(ipi); // fpi(ipi.operator int*()); fipi(ipi); // fipi(ipi); return ipi; // return ipi.operator int*(); } Here the value of the expression 'ipi' varies depending upon its context. Note: this behaviour is not precisely defined in E&S. X3J16 must carefully define disambiguation of multiple possible user-defined conversions. Here's what E&S has to say on the subject: %13.2, p. 326 "User-defined conversions are selected based on the type of variable being initialized or assigned to." But what if no variable is being initialized or assigned to, as in "*ipi", above? %12.3, p. 270 "User-defined conversions are applied only where they are unambiguous." Unfortunately, exactly what is "unambiguous" is ill-defined. In "*ipi", above, the situation is unambiguous because only ipi.operator int*(); works in the immediate context; "ipi.operator int()" cannot be dereferenced. Thus class PCDI { public: operator char*(); operator double*(); operator int*(); }; class PLCS { public: operator long*(); operator char*(); operator short*(); }; PCDI pcdi; PLCS plcs; plcs - pcdi; // plcs.operator char*() - pcdi.operator char*() only conversion to char* of both pcdi and plcs makes a valid expression; so there is no ambiguity!?! >how do you disambiguate? Even if you argue that you are converting the >return values to void , on the basis of what could you prefer one >conversion to void over another? Depends if "operator void()" is defined... :-) Jan Gray uunet!microsoft!jangr Microsoft Corp., Redmond Wash. 206-882-8080