Topic: why function return type not part of function signature ?


Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/05/29
Raw View
Stanley Friesen [Contractor] wrote:

> If "operator ." could be overloaded, it would probably be legal to return
> a Container::reference under the as if rule, so long as it overloaded
> operator & and operator . appropriately.

Absolutely not. The return type must a lvalue, so returning a
proxy isn't allowed.

PS: vector<bool> isn't a Container

The as-if rule has nothing to do with this problem.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/05/27
Raw View
AllanW wrote:
>
> In article <37330CAC.FDA@wanadoo.fr>,
>   Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> >
> > Try the following exercise:
> >
> > - make sure you understand all rules concerning overloading,
> >   name lookup, and template parameter deduction
> >
> > - make sure you fully understand all their interactions
> >
> > - read the standard again to make sure your understanding is
> >   correct
> >
> > - make up new rules for the extension you propose
> >
> > - see how they break programs
> >
> > - see how they make the damn thing even uglier and less
> >   understandable
> >
> > After you have finished the exercise, come back here or
> > in the committee and propose your idea.
>
> Mr. Bonnard, I'm shocked. This is much too flippant and dismissive.

Wonderful ! That was exactly my intent.

Why is it too much flippant ? It's just realistic.

My point is that after this exercise no one want to come
back to the committee and propose new things before a while.

Yes it is _very_ dismissive.

I tend to get tired of rants about features missing in C++.
Features don't appear unless someone formally proposes it.
This absolutely requires that he performs all the above steps.

Everything else cannot be taken seriously (but can definitely
be discussed).

But again, if you are shocked, it means that my previous
message (quoted above) wasn't pointless.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/05/21
Raw View
In article <t7pv47fsi1.fsf@calumny.jyacc.com>, Hyman Rosen
<hymie@prolifics.com> writes
>Regardless of whether C++ permits overloading by return type, I do think
>that type-safe linkage should use the return type information, so that
>accidental misdeclarations fail, just as they do for parameter mismatches.
>For most compilers, this means that I think that the return type should be
>part of the name mangling.

and AFAIK there is no reason why it should not be.  The implementor is
allowed to diagnose such problems and hence to put in place mechanisms
to support diagnosis.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/05/21
Raw View
On 10 May 99 12:34:47 GMT, Steve Clamage <clamage@eng.sun.com> wrote:

>[snip]
>that the rules are simple and easy to understand. Experts on
>the C++ committee amuse one another by posing simple examples
>(two or three functions of two or three arguments) and arguing
>about what the result is, or should be.

Give me an example!


>If overloading on return type is allowed, the type of a sub-
>expression would depend on the context in which it was invoked.
>That is, the version of a function that is invoked could depend
>on other parts of the expression. The compiler could no longer
>do a bottom-up type evaluation, but would have to push types down
>before evaluating bottom up. A programmer reading the code would
>have to do the same thing mentally in order to understand the code.

Good point.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/05/21
Raw View
In article <0996e1852220959CPIMSSMTPU07@email.msn.com>,
me@home.rutgers.edu says...

[ ... ]

> > x = f() + g(); // ???
>
> Quite simple, depending on the type of x and what "+" operators are defined.
> In the worst case compiler could give error because of ambiguity. It's not
> very different from the current situation.

Yes, it really is.  The situation right now is that `f()' can be
parsed on its own, and the compiler can either 1) figure out what to
call, or 2) figure out that there's an ambiguity and give an error.

By contrast, what you're talking about creating is an NP-complete
problem.  Given something like:

a() =  b() + c() + d() + e();

the compiler may have to try essentially _every_ possible combination
of b(), c(), d() and e() along with every overloading of operator+ for
the types they create, then try every overload of a() that produces an
lvalue to find whether one of them is compatible with one of the types
the expression on the right can produce (of course also dealing with
the fact that operator= might be overloaded as well...)

Just to pick some numbers, assume each of the functions has four
overloaded return types, and that each operator has a half-dozen
overloads between return types and operand types.  By my figuring that
means the compiler has to try over 4 million different combinations to
find the correct one for the expression above.  Worse yet, to
eliminate the possibility of ambiguity, the compiler has to try every
possible combination for _every_ expression, so it can tell you
there's an ambiguity if there's more than one.  The most obvious
alternative would be for the standard do say that if more than one
alternative exists, any of them might be chosen and you have no way of
deciding which.  The final possibility would be to prescribe a order
in which the search for alternatives would be conducted, basically
prescribing how a parser has to be written.

I'd note most current languages are defined to allow a parser to be
written _without_ having to do backtracking.  I.e. once it's parsed a
particular symbol as being of a particular type, it never tries to
make that symbol into something else.  There are a few ambiguities in
C and C++ that _would_ allow this situation to arise, but in every
case, it's been decided that when two alternatives are present, one
will be taken.  If it results in illegal code, the program is
considered illegal rather than the other alternative being explored.

As far as I can tell, parsing the language you describe would require
backtracking, which would require a complete rewrite of every parser
from beginning to end.  In particular, most tools for creating parsers
absolutely, positively do NOT provide any kind of support for back-
tracking at all.

About the only language around that requires backtracking in the
parser is FORTRAN.  FORTRAN caused enough of a problem that one of its
first implementors went on to help invent the Backus-Naur Form.  I'm
quite certain it's no accident that BNF simply doesn't allow you to
express a grammar that requires backtracking to parse...



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Adam Fowler" <adam@dma-design.com>
Date: 1999/05/21
Raw View
reference operator[](size_type pos) and const_reference operator[](size_type
pos) are both members of basic_string. It is possible to have both
operator[] functions because the const version is written

const_reference operator[](size_type pos) const;


Ed Brey <brey@afd.mke.etn.com> wrote in message
news:7hpjae$675@interserv.etn.com...
> As much as I would fret over the complexity overloading return types, other
> have detailed in this thread, I can think of one very practical use of the
> feature.  I present it through an example.
>
> Consider:
> template /*...*/ class basic_string {
>     // ...
>     reference operator[](size_type pos);
> };
>
> For a copy-on-write string, this is an expensive operation since the string
> must be copied.  Often, however, the returned value is only used in a
> constant manner.  Unfortunately, the compiler isn't allowed to look ahead
> into its AST to determine if the copy is really necessary.  It would be
> handy to add another function with an overload return type:
>
> const_reference operator[](size_type pos);
>
> or if the templatized character type is small enough:
>
> char_type operator[](size_type pos);
>
> Of course, this can be worked around by adding a member functions with a
> unique name such as:
>
> char_type at_const_no_bounds_check(size_type pos);
>
> The performance benefits of such a function appearently do not outweigh the
> muddying of the string interface that it would cause, as evidenced by its
> absense from the string class.
>
> It would appear that return value overloading could provide the best of both
> worlds in terms of readibility and performance.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1999/05/21
Raw View
Siemel Naran wrote:
....
> However, I think that in the standard library, Container::operator[]
> must return a real reference -- that is a Container::value_type&.

operator[] not required for general containers. It is an optional
sequence requirement, mandatory only for vector<> and deque<>. It must
return "container::reference", which is only required to be an "lvalue
of T". However, C++ makes it difficult (impossible?) to create a true
lvalue class, because "." and  and ".*" operators cannot be overriden.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/05/22
Raw View
On 21 May 1999 23:34:04 GMT, James Kuyper <kuyper@wizard.net> wrote:
>Siemel Naran wrote:

>> However, I think that in the standard library, Container::operator[]
>> must return a real reference -- that is a Container::value_type&.
>
>operator[] not required for general containers. It is an optional
>sequence requirement, mandatory only for vector<> and deque<>. It must
>return "container::reference", which is only required to be an "lvalue
>of T". However, C++ makes it difficult (impossible?) to create a true
>lvalue class, because "." and  and ".*" operators cannot be overriden.

No, you can create an lvalue class!  Eg,
   class T { ... };
   class container; // holds T objects
   class container::reference { ... T& operator() const; };
   class container::const_reference { ... const T& operator() const; };

Suppose we have a container C.  Then C[i] returns either a
container::reference or a container::const_reference.  The operator
conversion converts this to a T& or const T&, if appropriate.
   void f(C& c) { c[i].f(); } // calls T::f()
   void f(const C& c) { c[i].f(); } // calls T::f() const
   void g(C& c) { gg(c[i]); } // calls gg(T&)
   void g(const C& c) { gg(c[i]); } // calls gg(const T&)

There's one problem.  Suppose that theres a conversion
   /*not explicit*/ U::U(const T&);
and a function
   h(const U&);
Now suppose that container::operator[] returns a real reference or const
T&.  Then h(c[1]) converts c[1] of type const T& to const U&, and then
calls h(c[1]).
Now suppose that container::operator[] returns a nested class
const_reference.  Then h(c[1]) is an error because to go from type
container::const_reference to type const U& requires two conversion --
the operator conversion to extract the const T&, and then the
implicit constructor U::U(const T&).  The compiler is never allowed
to perform two user defined conversions.

The solution to this dilemma.  In the conversion from T to U, the
compiler is allowed to perform two user defined conversions, provided
that one of them is an operator conversion.  This rule sounds drastic
but really isn't because we shouldn't be using operator conversions
anyway.

And besides, it is usually not possible to return a real lvalue.  That
is, we can't have an operator const T&() const.  This is because an
lvalue probably doesn't exist.  An example: std::vector<bool> with
close packing.  So we go with an operator T() const.

So ...

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paresh Adhia" <noone@usa.net>
Date: 1999/05/19
Raw View

AllanW wrote in message <7hq3ce$3tu$1@nnrp1.deja.com>...
>Mr. Bonnard, I'm shocked. This is much too flippant and dismissive.
>
>Mr. Adhia wonders about a C++ language feature, and I'm sure he's
>not the only one. If I recall correctly, the first time that I
>read about this point it was STRONGLY STRESSED precisely because
>it is not obvious.

Thanks for making me feel that everyone with an opinion/question is welcome
to participate in this group. A language like C++ has no value, if it can't
be learned by majority of programmers and its expertise is kept to few
select people. Asking questions is the easiest way to better one's knowledge
and in the process may be to a better C++.

>
>Mr. Adhia, I can't give you all of the reasons why this rule
>exists. I believe that part of the reason is to make the job for
>compiler writers easier, but the language design rarely goes too
>far in that direction.
>
>I think that the primary goal in this case was to be able to
>look at ANY function call, even one deeply embedded within an
>expression, and be able to identify which function is called.
>Without this, there are just too many ambiguous cases.
>

Most posters have also expressed either of the two reasons viz. 1)
Complexity or 2) Poor design selection.
Many bright people have presented examples, similar to yours which depict
the complexity of implementing such a "feature" - if at all desirable.

However, now that I feel more encouraged of getting answers to questions
(however stupid they are) here are couple of more

In earlier posts, Siemel and Chistopher showed me a clever way to get around
this by writing a class with function call operators which return the types
I desire. Taking Siemel's example,

struct getQty {
      operator int() const;
      operator String() const;
   };
And to use
   int i=getQty(); // calls getQty::operator int() const
   String s=getQty(); // calls getQty::operator String() const

Wouldn't compiler need to parse or look at LHS to resolve which "function
call operator" to invoke ? How is this simpler to implement for compiler
than to overloaded function based on return type ? And since I am not very
familiar with how compilers are written, may be some one can explain me in a
little simpler words ?


>I don't really have the "killer" example ready, the one which
>would convince any reasonable reader that the only good way to
>deal with the issue is to ignore return types in function
>signatures. But these examples do exist.


I will not argue the fact that there are a lot more ways to use overloaded
functions that lead to poor readability than there are that actually improve
readability. Can following be one such minority example ?

int rand(); // return a random int value
double rand(); // return a random value between 0 and 1


Thanks

Paresh



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/19
Raw View
Valentin Bonnard wrote:
>
> Ed Brey wrote:
>
> > Of course, this can be worked around by adding a member functions with a
> > unique name such as:
> >
> > char_type at_const_no_bounds_check(size_type pos);
>
> It's spelled static_cast<const string&> (s) [pos], or
> ((const string&)s)[pos] if you aren't afraid of static
> casts.

And if you are, you use the following Const template:

template<class T>
 inline T const& Const(T const& t) { return t; }

Now you can just write

char ch = Const(mystr)[5];

This construct
- is more readable than the cast
- will not break if the type of mystr is changed (say, to wstring).

[...]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/05/19
Raw View
On 18 May 1999 23:36:45 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>Ed Brey wrote:

>>For a copy-on-write string, this is an expensive operation since the string
>>must be copied.  Often, however, the returned value is only used in a
>>constant manner.  Unfortunately, the compiler isn't allowed to look ahead
>>into its AST to determine if the copy is really necessary.  It would be
>>handy to add another function with an overload return type:

Not necessary.  We can have Container::operator[] return a nested class
Container::reference, which looks like this
   class Container::reference {
      public:
         reference& operator=(const value_type&); // write
         reference& operator=(const reference&); // write
         operator const value_type&() const; // read-only
      private:
         ...
   };
Now these two are different:
   cout << c[3]; // only call the read-only functions
   c[3]=3; // call the write functions


However, I think that in the standard library, Container::operator[]
must return a real reference -- that is a Container::value_type&.
I don't know the rationale for this restriction, except for one
thing: in going from T1 to T2, the compiler can only do one user
conversion, and the operator conversion is one of these.

>Or try to make your strings const when you can, and
>even with pass by value is used:
>
>void foo (CONST string s)
>{
>...
>}

Yes, and note that the declaration of the function in the header file can
leave out the const, ie.

   // foo.h
   namespace myspace
   {
   void foo(string);
   }

   // foo.c
   #include "foo.h"
   void myspace::foo(const string s) { ... } // ok!

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-dejanews.com
Date: 1999/05/19
Raw View
In article <7hq4v5$54s$1@nnrp1.deja.com>,
  AllanW <allan_w@my-dejanews.com> wrote:
>Why not go all the way?
>
>     class Haha {

"We were just kidding around, but you really went too far" (Barney
Gamble speaking to Homer Simpson :)

Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Matt Seitz" <mseitz@meridian-data.com>
Date: 1999/05/20
Raw View

Andy Glew <glew@cs.wisc.edu> wrote in message
news:3740BCBC.7114E188@cs.wisc.edu...
>
> > Stroustrup explains in "Design and Evolution" why overloading
> > on return type was deliberately excluded from C++. He'd seen
> > the problems it caused in Algol 68.
>
> Stroustrup  mentions problems, but doesn't say what they are
> (were)?

I couldn't find the reference in DESIGN AND EVOLUTION (if you could post the
section number, I would appreciate it).  However, in section 7.4.1 of THE
C++ LANGUAGE, Third Edition, Dr. Stroustrup writes:

"The reason is to keep resolution for an individual operator or function
call context-independent."

and

"If the return type were taken into account, it would no longer be possible
to look at a call of [an overloaded function] in isolation and determine
which function was called."




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/05/20
Raw View
"Ed Brey" <brey@afd.mke.etn.com> writes:

>As much as I would fret over the complexity overloading return types, other
>have detailed in this thread, I can think of one very practical use of the
>feature.

I don't think anyone has said the feature has no uses.

The question is whether the benefits outweigh the disadvantages.

In deciding to adopt any language feature we must consider not
just the benefits, but how widespread the benefits are: broadly
useful, occasionally useful, hardly ever useful? If you adopt
every feature anyone ever wanted in a language, you get an
unmanageable mess. (Some might argue the C++ has already reached
that point.)

Then consider the cost in language complexity: how hard is the
feature to teach, learn, understand, and use?  How does it
interact with other language features?

Stroustrup concluded that the costs far outweighed the benefits.
The C++ committee felt the same way. But of course, others might
have different opinions.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Hines" <chrishines@email.msn.com>
Date: 1999/05/20
Raw View
David R Tribble <dtribble@technologist.com> wrote in message
news:373B757A.15495E50@technologist.com...
>
> Steve Clamage <clamage@eng.sun.com> wrote
> >> The rules for overloading are so complex now that few people,
> >> if anyone, can correctly determine which function will be called
> >> in any but simple cases.
>
> "G.B." wrote:
> > No, programmers are not that dumb. Only in very intricate cases
> > people may have trouble determining correct behaviour. Again, this
> > type of overloading wouldn't change the situation dramatically.
>
> It's not a question of how dumb programmers are, but how complex
> the language is (already).
>
> >...
> > Example,
> >   unsigned Plus(unsigned, unsigned);
> >   double Plus(double,double);
> >   int i = Plus(1,2);  //???
> >
> > Solution? Simple: add return type specification:
> >   x = (int)f()+(int)g();
> > same as we use now
> >   int i= Plus((unsigned)1, (unsigned)2);
> >   int i= Plus(1u, 2u);
> >   int i= Plus(1., 2.);
>
> If you're willing to go through the trouble of adding type
> specifiers, type suffixes, and typecasts to disambiguate the calls,
> why not just give the overloaded functions slightly different names
> to begin with?  At least with different names the code is a little
> more obvious, and your maintenance programmers won't shoot you in
> the head.

It seems that we have two sets of goals that appear to be at odds with each
other.  On the one hand it would be nice if all of the functions that have
the same semantics also have the same name.  That is why overloading was
invented in the first place.  On the other hand, overloading based on return
type creates a host of problems for the human reader of the code and the
compiler.

There is a way to almost satisfy both sets of goals.  The solution is
already part of the C++ standard.  It is not fully implemented by all
compilers yet, but it shouldn't be too much longer (one can hope).

Templates, template specialization, and explicit specification of template
arguments form the building blocks of the solution.

Using the example cited above we can write:

template <T> T Plus(T lhs, T rhs) { return lhs + rhs; }

Or, suppose we have the following declarations:

template <T> T f() { ... }
template<> int f() { ... }    // template specialization
template<> double f() { ... }

template <T> T g() { ... }
template<> int g() { ... }
template<> double g() { ... }

Now we can write:

x = f<int>() + g<int>();
x = f<int>() + g<double>();

Similar techniques can be used for class member functions using member
function templates.

The down side is that by declaring the generic form of the template we allow
people to write:

x = f<my_type>() + g<your_type>();

Which may not be what we want.  We might want the template parameters to be
one of a select list of types.  I'm not sure if this is bad style or not.
I've seen many examples of template classes that expect only a subset of all
types as template parameters.  I have a feeling that templates, as defined
in C++, are inherently less strongly typed than the rest of the language.

Despite the obvious weakness, however, we now have functions with the same
name but different return types.  We also have a way to explicitly specify
the return type using existing C++ syntax.  Although it is not quite as
"simple" as implicit overloading, it does allow similarly named functions to
return different types.

Finally, the syntax bears a striking resemblance to the new form of type
casts.  For example, static_cast<int>(5.0).  I like this similarity.  We can
think of a cast as no more than a function that converts the type of its
argument to a new type that we specify.  It is this connection, in fact,
from which I derive the inspiration of this technique.  I first saw the idea
of a user defined type cast in "The C++ Programming Language" 3rd Ed.,
section 13.3.1, page 335.  If my examples are not obvious to you, take a
look at this section for more information.

--
    Chris Hines
    The sooner you start coding, the longer it will take you to finish.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stanley@West.Sun.COM (Stanley Friesen [Contractor])
Date: 1999/05/20
Raw View
In article <slrn7k61au.j1t.sbnaran@localhost.localdomain>,
Siemel Naran <sbnaran@uiuc.edu> wrote:
>
>Not necessary.  We can have Container::operator[] return a nested class
>Container::reference, which looks like this
>   class Container::reference {
>      public:
>         reference& operator=(const value_type&); // write
>         reference& operator=(const reference&); // write
>         operator const value_type&() const; // read-only
>      private:
>         ...
>   };
>Now these two are different:
>   cout << c[3]; // only call the read-only functions
>   c[3]=3; // call the write functions
>
>
>However, I think that in the standard library, Container::operator[]
>must return a real reference -- that is a Container::value_type&.
>I don't know the rationale for this restriction, ...

Consider the expression: c[3].value_func(x)

This is legal if Container::operator[] returns a real reference to the
value_type, but not if it returns a Container::reference.  This situation
obtains because it was decided not to allow overloading of "operator .".

If "operator ." could be overloaded, it would probably be legal to return
a Container::reference under the as if rule, so long as it overloaded
operator & and operator . appropriately.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW <allan_w@my-dejanews.com>
Date: 1999/05/17
Raw View
In article <37330CAC.FDA@wanadoo.fr>,
  Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>
> Try the following exercise:
>
> - make sure you understand all rules concerning overloading,
>   name lookup, and template parameter deduction
>
> - make sure you fully understand all their interactions
>
> - read the standard again to make sure your understanding is
>   correct
>
> - make up new rules for the extension you propose
>
> - see how they break programs
>
> - see how they make the damn thing even uglier and less
>   understandable
>
> After you have finished the exercise, come back here or
> in the committee and propose your idea.

Mr. Bonnard, I'm shocked. This is much too flippant and dismissive.

Mr. Adhia wonders about a C++ language feature, and I'm sure he's
not the only one. If I recall correctly, the first time that I
read about this point it was STRONGLY STRESSED precisely because
it is not obvious.

Mr. Adhia, I can't give you all of the reasons why this rule
exists. I believe that part of the reason is to make the job for
compiler writers easier, but the language design rarely goes too
far in that direction.

I think that the primary goal in this case was to be able to
look at ANY function call, even one deeply embedded within an
expression, and be able to identify which function is called.
Without this, there are just too many ambiguous cases.

Quick, which foo() does this call?

    long   foo(int version1);
    double foo(int version2);

    // ...
    if (foo(5) > foo(3)) { /* ... */ }

Assuming your rules are consistent, this either compares a long
to a long, or it compares a double to a double. But there's no
reason to prefer one over the other.

    long bar(int);

    // This prefers long foo(int), right?
    if (bar(5) > foo(5)) { /* ... */ }

    // But what about this one:
    if ((double)bar(5) > (double)foo(5)) { /* ... */ }
    // This calls two functions, each returns a long. Then it
    // casts the long to a double and compares. Right?
    // ...or...
    // This calls long bar(int) and casts the result to a double.
    // However, the notation (double)foo(5) forces us to call the
    // second version of foo, which returns a double directly.

I don't really have the "killer" example ready, the one which
would convince any reasonable reader that the only good way to
deal with the issue is to ignore return types in function
signatures. But these examples do exist.

----
Allan_W@my-dejanews.com is a "Spam Magnet" --
never read.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Hines" <chrishines@email.msn.com>
Date: 1999/05/18
Raw View
David R Tribble <dtribble@technologist.com> wrote in message
news:373B757A.15495E50@technologist.com...
>
> Steve Clamage <clamage@eng.sun.com> wrote
> >> The rules for overloading are so complex now that few people,
> >> if anyone, can correctly determine which function will be called
> >> in any but simple cases.
>
> "G.B." wrote:
> > No, programmers are not that dumb. Only in very intricate cases
> > people may have trouble determining correct behaviour. Again, this
> > type of overloading wouldn't change the situation dramatically.
>
> It's not a question of how dumb programmers are, but how complex
> the language is (already).
>
> >...
> > Example,
> >   unsigned Plus(unsigned, unsigned);
> >   double Plus(double,double);
> >   int i = Plus(1,2);  //???
> >
> > Solution? Simple: add return type specification:
> >   x = (int)f()+(int)g();
> > same as we use now
> >   int i= Plus((unsigned)1, (unsigned)2);
> >   int i= Plus(1u, 2u);
> >   int i= Plus(1., 2.);
>
> If you're willing to go through the trouble of adding type
> specifiers, type suffixes, and typecasts to disambiguate the calls,
> why not just give the overloaded functions slightly different names
> to begin with?  At least with different names the code is a little
> more obvious, and your maintenance programmers won't shoot you in
> the head.

It seems that we have two sets of goals that appear to be at odds with each
other.  On the one hand it would be nice if all of the functions that have
the same semantics also have the same name.  That is why overloading was
invented in the first place.  On the other hand, overloading based on return
type creates a host of problems for the human reader of the code and the
compiler.

There is a way to almost satisfy both sets of goals.  The solution is
already part of the C++ standard.  It is not fully implemented by all
compilers yet, but it shouldn't be too much longer (one can hope).

Templates, template specialization, and explicit specification of template
arguments form the building blocks of the solution.

Using the example cited above we can write:

template <T> T Plus(T lhs, T rhs) { return lhs + rhs; }

Or, suppose we have the following declarations:

template <T> T f() { ... }
template<> int f() { ... }    // template specialization
template<> double f() { ... }

template <T> T g() { ... }
template<> int g() { ... }
template<> double g() { ... }

Now we can write:

x = f<int>() + g<int>();
x = f<int>() + g<double>();

Similar techniques can be used for class member functions using member
function templates.

The down side is that by declaring the generic form of the template we allow
people to write:

x = f<my_type>() + g<your_type>();

Which may not be what we want.  We might want the template parameters to be
one of a select list of types.  I'm not sure if this is bad style or not.
I've seen many examples of template classes that expect only a subset of all
types as template parameters.  I have a feeling that templates, as defined
in C++, are inherently less strongly typed than the rest of the language.

Despite the obvious weakness, however, we now have functions with the same
name but different return types.  We also have a way to explicitly specify
the return type using existing C++ syntax.  Although it is not quite as
"simple" as implicit overloading, it does allow similarly named functions to
return different types.

Finally, the syntax bears a striking resemblance to the new form of type
casts.  For example, static_cast<int>(5.0).  I like this similarity.  We can
think of a cast as no more than a function that converts the type of its
argument to a new type that we specify.  It is this connection, in fact,
from which I derive the inspiration of this technique.  I first saw the idea
of a user defined type cast in "The C++ Programming Language" 3rd Ed.,
section 13.3.1, page 335.  If my examples are not obvious to you, take a
look at this section for more information.

--
    Chris Hines
    The sooner you start coding, the longer it will take you to finish.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: icedancer-zamboni@ibm-zamboni.net (Ken Walter)
Date: 1999/05/18
Raw View
On Tue, 18 May 1999 15:29:04, Andy Glew <glew@cs.wisc.edu> wrote:

>
>> Stroustrup explains in "Design and Evolution" why overloading
>> on return type was deliberately excluded from C++. He'd seen
>> the problems it caused in Algol 68.
>
Maybe he was refering to ADA where type matching was very complicated.
Including the result type means you need to look at the user of the
the result to choose the proper function.
The compiler would start with the assignment to see what
righthand sides were "allowed" and work its way down to the call.
Then if there was no exact match, casts could be inserted considering
both the result and operand.
It would be very easy for the programmer to get unexpected results.
Most programmers would not expect the definitions of the assignment
operator to cause a different function to be called.
If someone added a new assignment definition later, a
different function could be called.

Ken Walter

Remove -zamboni to reply
All the above is hearsay and the opinion of no one in particular
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW <allan_w@my-dejanews.com>
Date: 1999/05/18
Raw View
In article <7hhq0p$j49$1@nnrp1.deja.com>,
  gbush@my-dejanews.com wrote:
> The real usefullness of type
> overloading can be achieved if compiler could choose the right
> function
> based on additional information.
> One example would be the situation when virtual functions are defined
> in a class hierarchy, and some of them can return T& and some only T.
> The abstract base class could define both functions as purely virtual,
> and derived classes - define only those that are feasible. Then
> compiler could choose to use in expressions only those functions that
> are properly defined, ignoring abstract functions. That would also
> require to allow instantiation of abstract classes, but I don't see
> harm in it (even now it's possible to stumble over abstract function
> call.)
> Gene.

I don't know who's driving this discussion, but it just took a
sharp left turn.

Return types specify more than just the data type of the result.
They also specify the method used to get that result from the
function to the caller. (If this were not so, then there would
be no difference between a function return T and a function
returning T&). To choose at run-time between calling a
function returning T and a function returning T& would require
the caller to include code for handling either one of these
cases, or else it would require that both return types are
handled the same way.

Even for users it would be messy. If I'm going to call a
function and use the result to initialize a variable, what
type do I use for the variable? Now that the door has been
opened to allow virtual function implementations to return
different data types than the base classes declared, why stop
with T vs. T&? Why not go all the way?

    class Haha {
    public:
        double Hoho();
        virtual double Hoho1();
        virtual double Hoho2();
        virtual double Hoho3();
        virtual double Hoho4();
        virtual double Hoho5();
    };
    double Haha::Hoho() {
        switch (rand()%5)
        {
        case 0: return Hoho1();
        case 1: return Hoho2();
        case 2: return Hoho3();
        case 3: return Hoho4();
        case 4: return Hoho5();
        }
    }
    class YouLose: public Haha {
        virtual int* Hoho1() { static int x; return &x; }
        virtual void Hoho2() { }
        virtual double Hoho3() { return 0.1; }
        virtual ostream Hoho4() { return std::cout; }
        virtual vector<vector<char*> >& Hoho5() {
            static vector<char*> z;
            z.pushback("You lose!");
            return z;
        }
    }
    int main() {
        std::cout << "What will happen this time?" << std::endl;
        YouLose y;
        double result = y.Hoho();
        std::cout << "Didn't dump core this time! Got "
            << y << std::endl;
        return 0;
    }

----
Allan_W@my-dejanews.com is a "Spam Magnet" -- never read.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/05/18
Raw View
As much as I would fret over the complexity overloading return types, other
have detailed in this thread, I can think of one very practical use of the
feature.  I present it through an example.

Consider:
template /*...*/ class basic_string {
    // ...
    reference operator[](size_type pos);
};

For a copy-on-write string, this is an expensive operation since the string
must be copied.  Often, however, the returned value is only used in a
constant manner.  Unfortunately, the compiler isn't allowed to look ahead
into its AST to determine if the copy is really necessary.  It would be
handy to add another function with an overload return type:

const_reference operator[](size_type pos);

or if the templatized character type is small enough:

char_type operator[](size_type pos);

Of course, this can be worked around by adding a member functions with a
unique name such as:

char_type at_const_no_bounds_check(size_type pos);

The performance benefits of such a function appearently do not outweigh the
muddying of the string interface that it would cause, as evidenced by its
absense from the string class.

It would appear that return value overloading could provide the best of both
worlds in terms of readibility and performance.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/05/18
Raw View
Ed Brey wrote:

> Of course, this can be worked around by adding a member functions with a
> unique name such as:
>
> char_type at_const_no_bounds_check(size_type pos);

It's spelled static_cast<const string&> (s) [pos], or
((const string&)s)[pos] if you aren't afraid of static
casts.

Or try to make your strings const when you can, and
even with pass by value is used:

void foo (CONST string s)
{
...
}

> The performance benefits of such a function appearently do not outweigh the
> muddying of the string interface that it would cause, as evidenced by its
> absense from the string class.

Indeed

> It would appear that return value overloading could provide the best of both
> worlds in terms of readibility and performance.

You don't want overloading on return value.
You don't want overloading on return value.
You don't want ...

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Andy Glew <glew@cs.wisc.edu>
Date: 1999/05/18
Raw View
> Stroustrup explains in "Design and Evolution" why overloading
> on return type was deliberately excluded from C++. He'd seen
> the problems it caused in Algol 68.

Stroustrup  mentions problems, but doesn't say what they are
(were)?

I know Algol 68.

I never found the rules awkward.




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/11
Raw View
Paresh Adhia wrote:
>
> Hello Gurus,
>
> If answer to this question is obvious and "common-sense", please don't
> be harsh on me.
>
> I always wondered why is it that function return type is not part of
> function signature and parameters are.
>
> e.g. wouldn't it be nice to overload like,
>
> String getQty();
> int getQty();
> double getQty();
>
> instead of
>
> getStringQty();
> getIntQty();
> getDoubleQty();

[...]

You _can_ do it:

struct getQty
{
  operator string() { return "Hello world"; }
  operator int() { cout << "Hi there" << endl; return 3; }
  operator double()
    { cout << "I'm drunk - I see double ;-)" << endl; return 3.14; }
};

string s=getQty(); // s gets "Hello world"
int i=getQty(); // prints "Hi there", i gets 3
double d=getQty(); // prints "I'm drunk...", d gets 3.14

If you really need a function (f.ex. for member functions),
you can make it return a proxy object.

So it is possible - just with a different syntax.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/11
Raw View
Paresh Adhia wrote:
>
> >If you still think it should be that way do it as:
> >
> > class Qty {
> > Qty(...) {...}
> > friend Qty getQty();
> > public:
> > operator whatever() const { ... }
> > operator string() const { ... }
> > };
> > Qty const getQty() { return Qty(...); };
> >
>
> Hmm. I admit this approach is much cleaner and better than providing
> function overload based on return type.
>
> So function overload was not the best solution for my specific problem, but
> is it ALWAYS a bad idea ?
> Let me present some ideas (at the risk of upsetting some C++ hard-liners)
> I always thought (at least would like to think) that function returning
> values is just a notational convenience, much the same as C++ allows you
> "a+b" instead of "operator +(a,b)"
>
> E.g. had I declared those functions as
>
> void getQty(int &result);
> void getQty(String &result);
> void getQty(double &result);
>
> they would basically accomplish the same thing that I initially wanted, but
> without making C++ unhappy. So are we allowing a "bad design" practice
> through other loop-holes? If so, why then treat return value as second class
> citizen compared to parameters ? Some posters who replied to my original
> post, raised some question of adding complexity to language. I may be wrong
> again, but why would there be additional complexity ? Compiler can use
> existing rules it applies for matching parameter types to the return type as
> well.

[...]

Then consider the following expression:

y = f(g(x));

currently, the compiler can do the following:

- determine the type of x
- from that, determine the g() to be called, possibly add conversions
  to x
  this fixes the return type of g, and therefore the type passed to f
- from that, determine the f() to be called, possibly add conversions
  this determines the return type of f
- assign the result to x, possibly applying conversions.

If overloading on the return type were possible, the compiler might
have to consider more than one return type for g, each one with its
own set of allowed conversions. Moreover, for each of those
possibilities, there may be many possible return types for f, again
each with its own set of conversions. So the compiler cannot do
a simple inner-to-outer analysis, looking for the best fit for
each step separately, but it must determine all possible paths to
y, and then determine the best of all paths - with the difficulty
of defining preferences on complete paths instead of just single
invocations. And we haven't even touched templates yet...


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/05/11
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> Then consider the following expression:
> y = f(g(x));
> If overloading on the return type were possible

It's worth noting that Ada allows such overloading. I believe that there
is two-pass algorithm over an expression that enables the compiler to
determine whether types can be assigned uniquely or whether the expression
is ambiguous. And if Ada, which puts safety and readability as its first
priorities, allows it, then I don't see why C++ shouldn't ( :-) ? )

Regardless of whether C++ permits overloading by return type, I do think
that type-safe linkage should use the return type information, so that
accidental misdeclarations fail, just as they do for parameter mismatches.
For most compilers, this means that I think that the return type should be
part of the name mangling.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/05/14
Raw View
Steve Clamage <clamage@eng.sun.com> wrote
>> The rules for overloading are so complex now that few people,
>> if anyone, can correctly determine which function will be called
>> in any but simple cases.

"G.B." wrote:
> No, programmers are not that dumb. Only in very intricate cases
> people may have trouble determining correct behaviour. Again, this
> type of overloading wouldn't change the situation dramatically.

It's not a question of how dumb programmers are, but how complex
the language is (already).

>...
> Example,
>   unsigned Plus(unsigned, unsigned);
>   double Plus(double,double);
>   int i = Plus(1,2);  //???
>
> Solution? Simple: add return type specification:
>   x = (int)f()+(int)g();
> same as we use now
>   int i= Plus((unsigned)1, (unsigned)2);
>   int i= Plus(1u, 2u);
>   int i= Plus(1., 2.);

If you're willing to go through the trouble of adding type
specifiers, type suffixes, and typecasts to disambiguate the calls,
why not just give the overloaded functions slightly different names
to begin with?  At least with different names the code is a little
more obvious, and your maintenance programmers won't shoot you in
the head.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <dtribble@technologist.com>
Date: 1999/05/14
Raw View
superdude wrote:
>
> David R Tribble <dtribble@technologist.com> wrote
> > Consider some existing code that looks like:
> >
> >     extern int  getQuant();
> >
> >     double  quant;
> >     quant = getQuant();
> >
> > It compiles and runs just fine without complaint.
> >
> > Now I come along and add an overloaded function with the same
> > name (presumably to the header file that contains the declaration
> > of getQuant()):
> >
> >     extern float  getQuant();
> >
> > Now my poor code breaks.  It had a very well-defined meaning before
> > I added the second function, but now it's unclear what I really
>
> Well, it's a lame excuse :)
> The situations like that are already a reality.
>  Consider some existing code that looks like:
>
> void f(unsigned);
> ...
> f(1);
>
> It compiles and runs just fine without complaint.
> Now I come along and add an overloaded function:
>
> void f(double);
> Now my poor code breaks... Ooops.

Except that now the compiler tells you it's ambiguous (or something
like that), so you have a fighting chance of knowing about it and
fixing it.  The compiler would not be so kind in my example, and
silently alter the behavior of the code.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: gbush@my-dejanews.com
Date: 1999/05/14
Raw View
In article <373B757A.15495E50@technologist.com>,
  David R Tribble <dtribble@technologist.com> wrote:
> If you're willing to go through the trouble of adding type
> specifiers, type suffixes, and typecasts to disambiguate the calls,
> why not just give the overloaded functions slightly different names
> to begin with?  At least with different names the code is a little
> more obvious, and your maintenance programmers won't shoot you in
> the head.
I don't say typecasts is useful feature, it's just an example how it is
possible to disambiguate some constructs. The real usefullness of type
overloading can be achieved if compiler could choose the right function
based on additional information.
One example would be the situation when virtual functions are defined
in a class hierarchy, and some of them can return T& and some only T.
The abstract base class could define both functions as purely virtual,
and derived classes - define only those that are feasible. Then
compiler could choose to use in expressions only those functions that
are properly defined, ignoring abstract functions. That would also
require to allow instantiation of abstract classes, but I don't see
harm in it (even now it's possible to stumble over abstract function
call.)
Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "G.B." <me@home.rutgers.edu>
Date: 1999/05/10
Raw View

Steve Clamage <clamage@eng.sun.com> wrote in message
news:7gvvuc$7tv$1@engnews1.eng.sun.com...
> Because you don't want to overload on return type.

Sometimes you do want that. And real-life examples are easy to present.

> The rules for overloading are so complex now that few people,
> if anyone, can correctly determine which function will be called
> in any but simple cases.

No, programmers are not that dumb. Only in very intricate cases people may
have trouble determining correct behaviour. Again, this type of overloading
wouldn't change the situation dramatically.

> x = f() + g(); // ???

Quite simple, depending on the type of x and what "+" operators are defined.
In the worst case compiler could give error because of ambiguity. It's not
very different from the current situation. Example,

unsigned Plus(unsigned, unsigned);
double Plus(double,double);
int i = Plus(1,2);  //???

Solution? Simple: add return type specification:
x= (int)f()+(int)g();
same as we use now
int i= Plus((unsigned)1, (unsigned)2);
int i= Plus(1u, 2u);
int i= Plus(1., 2.);

Gene.





[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "superdude" <uunet!home!me@ncar.ucar.edu>
Date: 1999/05/10
Raw View
David R Tribble <dtribble@technologist.com> wrote in message
news:373349B3.5B4C680E@technologist.com...
> Consider some existing code that looks like:
>
>     extern int  getQuant();
>
>     double  quant;
>     quant = getQuant();
>
> It compiles and runs just fine without complaint.
>
> Now I come along and add an overloaded function with the same
> name (presumably to the header file that contains the declaration
> of getQuant()):
>
>     extern float  getQuant();
>
> Now my poor code breaks.  It had a very well-defined meaning before
> I added the second function, but now it's unclear what I really

Well, it's a lame excuse :)
The situations like that are already a reality.
 Consider some existing code that looks like:

void f(unsigned);
...
f(1);

It compiles and runs just fine without complaint.
Now I come along and add an overloaded function:

void f(double);
Now my poor code breaks... Ooops.

Gene.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/05/10
Raw View
"G.B." <me@home.rutgers.edu> writes:

>Steve Clamage <clamage@eng.sun.com> wrote in message
>news:7gvvuc$7tv$1@engnews1.eng.sun.com...
>> Because you don't want to overload on return type.

>Sometimes you do want that. And real-life examples are easy to present.

I meant that you shouldn't want to do so in general.

>> The rules for overloading are so complex now that few people,
>> if anyone, can correctly determine which function will be called
>> in any but simple cases.

>No, programmers are not that dumb.

I'm not saying programmers are dumb. I'm saying the overloading
rules are quite complex. The C++ Committee spent years trying to
tweak the rules so that programmers would get fewer surprises from
reasonable-looking code. Every set of rules tried led to some
surprising results.

>Only in very intricate cases people may
>have trouble determining correct behaviour. Again, this type of overloading
>wouldn't change the situation dramatically.

The part of the standard describing overloading is 25 pages long.
Of those, 14 pages are devoted to the rules for resolving a
call to an overloaded function.  You cannot seriously claim
that the rules are simple and easy to understand. Experts on
the C++ committee amuse one another by posing simple examples
(two or three functions of two or three arguments) and arguing
about what the result is, or should be.

>> x = f() + g(); // ???

>Quite simple, depending on the type of x and what "+" operators are defined.
>In the worst case compiler could give error because of ambiguity. ...

>Solution? Simple: add return type specification:
>x= (int)f()+(int)g();
>same as we use now
>int i= Plus((unsigned)1, (unsigned)2);
>int i= Plus(1u, 2u);
>int i= Plus(1., 2.);

It's not simple, and it's not the same.

Currently in C++, the type of a unary or binary expression is
determined solely by the operator and its operands. The surrounding
context is not considered.

If overloading on return type is allowed, the type of a sub-
expression would depend on the context in which it was invoked.
That is, the version of a function that is invoked could depend
on other parts of the expression. The compiler could no longer
do a bottom-up type evaluation, but would have to push types down
before evaluating bottom up. A programmer reading the code would
have to do the same thing mentally in order to understand the code.

You have to ask what sort of programs you could write that you
cannot write easily now, in exchange for the added complications
in implementing, teaching, and understanding the language. IMHO
(and I am not alone in this) the cost is too high.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/05/07
Raw View
In article <3731B473.BC0F7D42@usa.net>, Paresh Adhia <noone@usa.net>
writes
>Hello Gurus,
>
>If answer to this question is obvious and "common-sense", please don't
>be harsh on me.
>
>I always wondered why is it that function return type is not part of
>function signature and parameters are.
>
>e.g. wouldn't it be nice to overload like,
>
>String getQty();
>int getQty();
>double getQty();

[Moderator note: quotation reduced --vb]

How do you propose to use such functions in expressions?  Yes, of course
it can be done but at a cost in further complicating compilers.

However there is a more fundamental reason, well designed overload
functions all do conceptually the same thing.  They only differ in the
data they use.  If the data is the same then...?

>
>To resolve above ambiguity, why can't language allow something like,
>
>(double) getQty(); // remove ambiguity and ignore return value

having more places for casts is just to add further chances of getting
it wrong.
>
>The other alternative, I could think of was to provide type conversion
>operators between various return types, but that approach is dangerous
>as it will be applicable too generally.
>


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <dtribble@technologist.com>
Date: 1999/05/07
Raw View
Paresh Adhia wrote:
> I always wondered why is it that function return type is not part of
> function signature and parameters are.
>
> e.g. wouldn't it be nice to overload like,
>
> String getQty();
> int getQty();
> double getQty();
>
> instead of
>
> getStringQty();
> getIntQty();
> getDoubleQty();

Consider some existing code that looks like:

    extern int  getQuant();

    double  quant;
    quant = getQuant();

It compiles and runs just fine without complaint.

Now I come along and add an overloaded function with the same
name (presumably to the header file that contains the declaration
of getQuant()):

    extern float  getQuant();

Now my poor code breaks.  It had a very well-defined meaning before
I added the second function, but now it's unclear what I really
mean.  If the compiler now silently chooses the new function instead
of the old one, I could have some real problems.

-- David R. Tribble, dtribble@technologist.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/05/08
Raw View
Paresh Adhia wrote:
>
> Hello Gurus,
>
> If answer to this question is obvious and "common-sense", please don't
> be harsh on me.
>
> I always wondered why is it that function return type is not part of
> function signature and parameters are.
>
> e.g. wouldn't it be nice to overload like,
>
> String getQty();
> int getQty();
> double getQty();
>
> instead of
>
> getStringQty();
> getIntQty();
> getDoubleQty();

If you really want to do this, you can (almost) get the behaviour you want.
But first reconsider your design. Do getStringQty(), getIntQty() and
getDoubleQty() really return the _same_ Qty. (In case of int and double I
really doubt).
I suppose this might be more ok with
 whatever getQty();
 string getQtyAsString();
if you really can't leave the formatting to whatever.
If you still think it should be that way do it as:

 class Qty {
  Qty(...) {...}
  friend Qty getQty();
 public:
  operator whatever() const { ... }
  operator string() const { ... }
 };
 Qty const getQty() { return Qty(...); };

Of course Qty cannot be used in every context, where a whatever rvalue is
required. But especially eliminating further user-defined conversions makes
the program's behaviour easier to understand.
If you understand why such code (involving user-defined implicit conversions)
may lead to trouble, you get a hunch of the difficulties inherent in your
proposal: it would allow expressions which effectivcely involve two
user-defined conversions - one based on 'overload' resolution and one as
normal. The diffuculty of this for compilers and for readers of your program
would be immense.

-- J   rg Barfurth


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/05/09
Raw View
Paresh Adhia <noone@usa.net> writes:

>I always wondered why is it that function return type is not part of
>function signature and parameters are.

Because you don't want to overload on return type.

>e.g. wouldn't it be nice to overload like,

>String getQty();
>int getQty();
>double getQty();

No, it wouldn't.

The rules for overloading are so complex now that few people,
if anyone, can correctly determine which function will be called
in any but simple cases.

Adding the capability to overload on return type would make the
situation worse, apart from adding many more opportunities for
ambiguity.

 int f();
 double f();
 long g();
 float g();
 ...
 x = f() + g(); // ???

Stroustrup explains in "Design and Evolution" why overloading
on return type was deliberately excluded from C++. He'd seen
the problems it caused in Algol 68.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/05/09
Raw View
On 07 May 99 14:22:18 GMT, Paresh Adhia <noone@usa.net> wrote:

>e.g. wouldn't it be nice to overload like,
>
>String getQty();
>int getQty();
>double getQty();

In the absence of overloading by return value, the expressions "getQty()",
"a+b", and "3/4" are well defined.  Just look at the argument types and
determine which function to call.  For example, "3/4" calls
operator/(int,int), and the answer is zero.

But in the presence of overloading by return value, the same expressions
are not well defined.  We have to look at the type declaration to
determine which function to call --
   String s=getQty(); // call String getQty()
   int s=getQty(); // call int getQty()
In other words, the meaning of an expression depends on the context in
which it is used.  Even if this sort of thing were possible, it would
make program maintainance much more difficult.


>The other alternative, I could think of was to provide type conversion
>operators between various return types, but that approach is dangerous
>as it will be applicable too generally.

Actually, I'll let you in on a secret.  You can overload by return
value in C++.
   struct getQty {
      operator int() const;
      operator String() const;
   };
And to use
   int i=getQty(); // calls getQty::operator int() const
   String s=getQty(); // calls getQty::operator String() const

Technically, this is not overloading by return value.
Practically, it is.

But I think it will lead to code that is hard to maintain, so my
recommendation is to stay away from it.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paresh Adhia" <noone@usa.net>
Date: 1999/05/09
Raw View
>If you still think it should be that way do it as:
>
> class Qty {
> Qty(...) {...}
> friend Qty getQty();
> public:
> operator whatever() const { ... }
> operator string() const { ... }
> };
> Qty const getQty() { return Qty(...); };
>

Hmm. I admit this approach is much cleaner and better than providing
function overload based on return type.

So function overload was not the best solution for my specific problem, but
is it ALWAYS a bad idea ?
Let me present some ideas (at the risk of upsetting some C++ hard-liners)
I always thought (at least would like to think) that function returning
values is just a notational convenience, much the same as C++ allows you
"a+b" instead of "operator +(a,b)"

E.g. had I declared those functions as

void getQty(int &result);
void getQty(String &result);
void getQty(double &result);

they would basically accomplish the same thing that I initially wanted, but
without making C++ unhappy. So are we allowing a "bad design" practice
through other loop-holes? If so, why then treat return value as second class
citizen compared to parameters ? Some posters who replied to my original
post, raised some question of adding complexity to language. I may be wrong
again, but why would there be additional complexity ? Compiler can use
existing rules it applies for matching parameter types to the return type as
well. e.g.

getQty("a char array")

would cause compiler to pick

getQty(String)

Similarly, when used in expression such as,

String a, b;
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Paresh Adhia <noone@usa.net>
Date: 1999/05/07
Raw View
Hello Gurus,

If answer to this question is obvious and "common-sense", please don't
be harsh on me.

I always wondered why is it that function return type is not part of
function signature and parameters are.

e.g. wouldn't it be nice to overload like,

String getQty();
int getQty();
double getQty();

instead of

getStringQty();
getIntQty();
getDoubleQty();

Note : I have selected very simple example for illustration, I know
standard conversion will convert from double to int)

The only reason that I can think of not allowing this type of
overloading is when the returned value is ignored. i.e.

getQty();

Can't compiler flag such references as "ambiguous" only when used in
such context ? I think we have other constructs in C++ that might lead
to ambiguity, but language allows them and are flagged only when used
in ambiguous way.

To resolve above ambiguity, why can't language allow something like,

(double) getQty(); // remove ambiguity and ignore return value

The other alternative, I could think of was to provide type conversion
operators between various return types, but that approach is dangerous
as it will be applicable too generally.

BTW, unless return type is a simple one, don't most modern compilers
pass the address of receiving variable to the called function anyway to
save a constructor call ? How this case is handled when the returned
value is ignored ? compiler created dummy receiving variable ?

TIA

Paresh

P.S. my slogan for C++
I will rather have a "write once compile everywhere" program than a
poor performing "write once run everywhere" program.

This communication is for informational purposes only.  It is not intended as
an offer or solicitation for the purchase or sale of any financial instrument
or as an official confirmation of any transaction, unless specifically agreed
otherwise. All market prices, data and other information are not warranted as
to completeness or accuracy and is subject to change without notice. Any
comments or statements made herein do not necessarily reflect those of
J.P. Morgan & Co. Incorporated, its subsidiaries and affiliates.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/05/07
Raw View
Try the following exercise:

- make sure you understand all rules concerning overloading,
  name lookup, and template parameter deduction

- make sure you fully understand all their interactions

- read the standard again to make sure your understanding is
  correct

- make up new rules for the extension you propose

- see how they break programs

- see how they make the damn thing even uglier and less
  understandable

After you have finished the exercise, come back here or
in the committee and propose your idea.

--

Valentin Bonnard


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]