Topic: Declaring member functions outside of the class definition


Author: "Bill Wade" <wrwade@swbell.net>
Date: Mon, 29 Apr 2002 16:59:35 GMT
Raw View
"Matthew Dempsky" <jivera@flame.org> wrote

> Can anyone see a reason not to introduce a mechanism to the language to
> let people declare non-virtual member functions outside of the class
> defintion?

One problem with C++ is that it is easy to inadvertantly have new functions
silently change the meaning of existing programs, because the new function
is a better match for overload resolution.

One advantage of member function notation is that it significantly restricts
the functions to be considered, reducing the likelyhood that "surprising"
overloads will win.

The proposed mechanism would eliminate the advantage.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 27 Mar 2002 18:21:36 GMT
Raw View
In article <pan.2002.03.26.22.53.09.944.7246@flame.org>, "Matthew Dempsky"
<jivera@flame.org> wrote:
>> http://www.nondot.org/~sabre/Projects/CXX/NameLookup.html
...
>It is interesting and I had thoughts about it before, but not to the
>extent you go into. There were some backwards compatibility issues I was
>worried with using that idea earlier, but I can't think of them at the
>moment so I'll have to post them later.

The idea to make f(x, y) and x.f(y) equivalent was discussed here before,
but I do not recall which thread; further, we arrived at an interesting
extension:

Instead of
  class X {
    virtual f(Y) ...
  };
one might write
  class X {
    f(virtual X, Y) ...
  };
This might be extended, so that one writes in this "virtual" on a selected
argument:
  class X {
    f(Y_1, ..., Y_j, virtual X, Z_1, ..., Z_n) ...
  };

The idea is to avoid having to introduce extra names for functions like
operator<<. Instead of:

  class X {
  public:
    virtual write(std::ostream&) ...
  };

  std::ostream& operator<<(std::ostream& os, const X& x) {
    x.write(os);
    return os;
  }

one can directly write:
  class X {
  public:
    std::ostream& operator<<(std::ostream&, virtual const X&) ...
  };

Thus, without having to introduce the intermediate function "write".

>One question I am wondering about is would the ability to call functions
>as methods extend to primitives like int and float? e.g. Would the
>following become legal?
>
>float foo = 45.0;
>float bar = foo.sin();

The operator<< example suggests that functions that are not defined within
a class remain global, and cannot use the "." syntax. Only functions
declared within the class body can belong to the class.

For class functions, the "." notation and functional notation can be used
interchangeable if one knows which argument belongs to the class. For
virtual functions, this was indicated above by the word "virtual". For
non-virtual, one will have to use another keyword, say "!virtual", to
indicate it. (But I almost exclusively program with polymorphic classes,
so I have not given that much thought.)

This is in the line with the original intentions of a class interface
(that outsiders should not be able to alter it, and make traditional
static compilation of classes possible).

Otherwise, I have not given much thought of the details on how to
implement this idea: I think that if one is a C++ compiler writer, one
could fiddle around with it to quickly see if it can be made working, and
what the limits are.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: John Levon <moz@compsoc.man.ac.uk>
Date: Wed, 27 Mar 2002 18:58:12 GMT
Raw View
Matthew Dempsky wrote:

> I just noticed a flaw (maybe) in your "object oriented C to C++" example -
> fread accepts the FILE* parameter as the last parameter, not the first
> (along with a few other functions - fputc, fputs, freopen, and fwrite).
> Thus the compiler would need to be smart enough to rearrange F->fread(...)
> to fread(..., F) instead of fread(F, ...)

Ugh.

The system can simply provide fread(FILE * fp, ...

The overloading rules should prefer the FILE * above the void *, and
everything should work out OK without the need for the obscure
manipulations you suggest.

There's a good readability reason for always preferring operations on
objects to be of the form obj.operation(params).

The non-member style loses information :

 doSomething(obj, obj2, obj3);

does not delineate between the subject and the other actors in the
operation half as well as :

 obj.doSomething(obj2, obj3);

This is the main reason I prefer the dot notation wherever sensible...

regards
john

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Matthew Dempsky" <jivera@flame.org>
Date: Tue, 26 Mar 2002 00:00:10 GMT
Raw View
((I already tried posting something similar to this at
comp.lang.c++.moderated, and got a few good replies, but not as many as I
was expecting.))

Surely everyone has heard Scott Meyers's arguement about using non-friend
non-member functions to improve encapsulation. I understand the idea and
would agree with it except I don't really enjoy typing ``Nap(wombat)''
when instead I could ``wombat.Nap()''.

Can anyone see a reason not to introduce a mechanism to the language to
let people declare non-virtual member functions outside of the class
defintion? Of course those member functions should only have access to the
public interface of the class so encapsulation isn't compromised.

Similar to how `friend' gives other functions/classes access to the
class's private and protected data, these external member-functions would
be under the influence of what I've been calling `helper', but that name
isn't necessary to actually be used unless you wanted to let library
writers define member functions with restricted access within the class
definition (as opposed to elsewhere where it's less natural for library
implementers
 to look). Other names would work just as well, `foe', `enemy',
`rival'... `~friend' was also proposed by Francis Glassborow so that a new
keyword doesn't need to be introduced per se.

What are your thoughts on this? If I need to expand a little further, I'll
gladly do so.

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Chris Lattner<sabre@nondot.org>
Date: Tue, 26 Mar 2002 15:55:09 GMT
Raw View
Matthew Dempsky <jivera@flame.org> wrote:
> Can anyone see a reason not to introduce a mechanism to the language to
> let people declare non-virtual member functions outside of the class
> defintion? Of course those member functions should only have access to the
> public interface of the class so encapsulation isn't compromised.

This might be of interest to you:

http://www.nondot.org/~sabre/Projects/CXX/NameLookup.html

Although I have not updated the document in a long time, I still think it is
a very useful extension to C++, which could help alleviate, f.e:

1. The discrepency between x.find() and find(x.begin(), x.end(), ...) in
   the STL containers
2. The fact that overloaded operators already operated exactly like this.

-Chris

http://www.nondot.org/~sabre

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 26 Mar 2002 20:15:13 GMT
Raw View
In article <pan.2002.03.25.17.47.30.764.16414@flame.org>, Matthew
Dempsky <jivera@flame.org> writes
>Other names would work just as well, `foe', `enemy',
>`rival'... `~friend' was also proposed by Francis Glassborow so that a new
>keyword doesn't need to be introduced per se.

However that should not be taken as meaning I support the proposal. It
might also be noted that 'not' is also a keyword so we could write 'not
friend' or have 'not virtual' as a kind of 'final' etc.


--
Francis Glassborow
Check out the ACCU Spring Conference 2002
4 Days, 4 tracks, 4+ languages, World class speakers
For details see: http://www.accu.org/events/public/accu0204.htm

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]





Author: "Matthew Dempsky" <jivera@flame.org>
Date: Wed, 27 Mar 2002 04:53:41 GMT
Raw View
In article <7gTn8.32370$tg4.378232@vixen.cso.uiuc.edu>, "Chris Lattner"
<sabre@nondot.org> wrote:

> This might be of interest to you:
>
> http://www.nondot.org/~sabre/Projects/CXX/NameLookup.html
>
> Although I have not updated the document in a long time, I still think
> it is a very useful extension to C++, which could help alleviate, f.e:
>
> 1. The discrepency between x.find() and find(x.begin(), x.end(), ...) in
>    the STL containers
> 2. The fact that overloaded operators already operated exactly like
> this.

It is interesting and I had thoughts about it before, but not to the
extent you go into. There were some backwards compatibility issues I was
worried with using that idea earlier, but I can't think of them at the
moment so I'll have to post them later.

One question I am wondering about is would the ability to call functions
as methods extend to primitives like int and float? e.g. Would the
following become legal?

float foo = 45.0;
float bar = foo.sin();

Since sin() uses a value instead of a pointer or reference it'd appear to
work differently. However, if the compiler looked at the problem this way,
it might become simpler:

Check if sin() is a member function of float If it is then treat it as
normal
If not, rearrance the function as per these rules:
  foo.sin()  => sin(foo)
  foo->sin() => sin(*foo)
If that is legal then handle it that way If not, give an error

This would basically rule that `this' needs to either be a reference
parameter (or const ref for const methods) or be a value parameter and
needs to be the first parameter of the function. Unfortunately, using this
method, `this' would be a reference in non-member functions and a pointer
in member-functions. (Since `this' is a const pointer in member functions,
it could be changed to a reference and have no problems except in legacy
code where it's used explicitly.)

I just noticed a flaw (maybe) in your "object oriented C to C++" example -
fread accepts the FILE* parameter as the last parameter, not the first
(along with a few other functions - fputc, fputs, freopen, and fwrite).
Thus the compiler would need to be smart enough to rearrange F->fread(...)
to fread(..., F) instead of fread(F, ...) (though using the method I
described above, you'd end up needing to use F.fread(...)). Of course the
above outline for how the compiler should find the function could be
extended that if passing the object as the first parameter isn't legal it
could then check if it's legal as the last parameter or something similar.
Further, passing it as the final parameter without casting would probably
need to be prefered over passing it as the first parameter with casting (I
can't think of an example of why I think this would be necessary off hand,
but if I need to elaborate I'll try to find one.)

---
[ 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://www.research.att.com/~austern/csc/faq.html                ]