[comp.std.c++] Using return datum type in function signature

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