Topic: Language Question: Why privates in header


Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Mon, 27 Dec 1993 13:50:46 GMT
Raw View
In article <1993Dec22.220307.18449@csrd.uiuc.edu> harrison@sp10.csrd.uiuc.edu (Luddy Harrison) writes:
>It strikes me that John Max Skaller's proposal
>to permit private, non-virtual
>member functions to be omitted from a class declaration
>goes only a small way toward hiding the implementation
>of a class.

 Yes, that is true. It goes as far as can be gone I think,
without requiring some form of 'binder' or super linker that
can perform magic calculations in which 'sizeof' is not known
at compile time, but gets filled in later. Or something :-)

>Often what gives me the greatest problem
>in providing an interface is the private data members.
[]
>
>Add to this that private virtual functions would
>still be required to be declared, and I think that this
>proposal adds yet more complexity to the language with
>too little in return.

 Perhaps this is true. However, there is a distinction
I think between determining the data required to represent
the state of an object, and deciding how to implement
the methods. The former is often simple and fixed,
and the only extensions are usually things like caches.

 On the other hand, there is little added complexity.
We already have namespaces, and PREVENTING definition
of members in an extension namespace of a class requires
a special rule (restriction). SO allowing this:

 class X { void f(); };
 namespace X { void f() { .. } };

doesn't seem to add any complexity to me: in fact
it looks much like:

 void X::f() { .. }

except that the return type in the latter is in the wrong
scope :-(

In particular I'd find this:

 class X { void f(); void g(); void h(); void k(); };
 namespace X {
  void f() { .. }
  void g() { .. }
  void h() { .. }
  void k() { .. }
 }

easier to read perhaps than

  void X::f() { .. }
  void X::g() { .. }
  void X::h() { .. }
  void X::k() { .. }

In BOTH cases, I have to reopen the scope of the class to
define a function. All that differs seems to be the particular
syntactic construct used to do that. And the first method
is already allowed for namespaces that are not classes anyhow.

>There needs badly to be a separation
>between implementation and interface, and to be a sensible
>solution the separation must pertain to data members
>and virtual functions, as well as private member functions.

 Private virtual are interesting. In particular
I have a paradigm where ALL virtual functions are
required to be virtual. In this paradigm, there cannot
be any virtual calls except from member functions
of the class in which the original virtual is declared.

 Private virtuals can still be overriden. And doing
so is an implementation detail. And in my paradigm,
all virtual functions are implementation details :-)

>
>Of course, template classes add another dimension to the
>problem of providing an interface without exposing an
>implementation.

 The solution to this is already required.

>If a library provides template classes, it
>must provide declarations as well as definitions of
>all of the member functions, virtual or otherwise.  If
>template classes constitute any appreciable fraction of
>an interface, then the band-aid of allowing private, non-virtual
>member functions to be omitted is seen to be even less
>satisfactory as a solution to the general problem.

 Yes, if we didnt have namespaces it would
be problematical. But from a pragmatic point of view,
the solution reduces some of the burden at little cost:
we already do have namespaces, and much of the time the
big problem is functional decomposition of member
function definitions.

 So, yes, its still problematical. But then,
so is C++. You can use Modula or Eiffel if you really
cant live with the constraints of C++.

 Or, design D :-)



--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 27 Dec 1993 17:18:04 GMT
Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:

> Private virtual are interesting. In particular
>I have a paradigm where ALL virtual functions are
>required to be virtual.

Huh?  Did you mean they're all required to be public?

>In this paradigm, there cannot
>be any virtual calls except from member functions
>of the class in which the original virtual is declared.
>
> Private virtuals can still be overriden. And doing
>so is an implementation detail. And in my paradigm,
>all virtual functions are implementation details :-)

[...]
> Or, design D :-)

... and implement it, and market it.  Good luck.

--
Fergus Henderson        |   "People who brook no compromise in programming
                        |   languages should program in lambda calculus or
fjh@munta.cs.mu.OZ.AU   |   machine language, depending." --Andrew Koenig.




Author: harrison@sp1.csrd.uiuc.edu (Luddy Harrison)
Date: Mon, 27 Dec 93 19:11:22 GMT
Raw View
I write:

>>Add to this that private virtual functions would
>>still be required to be declared, and I think that this
>>proposal adds yet more complexity to the language with
>>too little in return.

To which John replies:
> ...
> On the other hand, there is little added complexity.

The complexity that I had in mind was complexity from
the point of view of the programmer, not of the C++
implementor.  The latter fellow is already being boiled
alive in a stew of complexity, he will hardly notice
the difference.

What I meant was this: at present, one may examine the
declaration of a class and from it obtain an exhaustive
list of the functions which may mention a private data
member by name.  In my mind, this is one of the few
assurances of modularity provided by the language.  If
we dispense with this assurance (in favor of being
able to add private member functions outside the declaration
of the class), it will come at a cost of (conceptual)
complexity: we will now be forced to search through source
files to obtain the list of functions that might touch
a private data member.  (You mentioned this in an earlier
posting.)  I was questioning whether this
was a sensible tradeoff, in light of the fact that it
does not genuinely solve the problem of separating interface
from implementation.

-Luddy Harrison




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Thu, 30 Dec 1993 14:17:39 GMT
Raw View
In article <9336204.6143@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>> Private virtual are interesting. In particular
>>I have a paradigm where ALL virtual functions are
>>required to be virtual.
>
>Huh?  Did you mean they're all required to be public?

 Oh, sorry, excuse the typo: No, I meant they're all
required to be PRIVATE:

 class X {
  virtual void vf()=0;
 public:
  void f() { vf(); }
 };

Public members are NOT hidden in derived classes, but the
private virtuals are overridden:

 class Y : public virtual X {
  void vf() { }
 };

Here in particular the static call is the only one that should
be used by anyone: the ONLY virtual call is the one made
by the member void f().

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sun, 19 Dec 1993 12:08:17 GMT
Raw View
In article <konigsba.756170673@cambridge> konigsba@cambridge.mitchell.com (Dan Konigsbach) writes:
>On the topic of allowing private, non-virtual functions not to be included
>in a class header...
>
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>
>[Stuff deleted]
>
>> Easy. Private helper are not allowed to be virtual.
>>A private virtual is very much part of the interface.
>
>I think that hiding the details of the implementation is a great
>benefit.

 Me too.
>
>I apologize if these were discussed earlier in the thread, but
>just in case not, here are two points to consider:
>
>1.  If a private method has the same signature as a non-private
>    method of a base class, then this BOTH declares the private
>    method AND changes the accessibility of the name.

 Make it illegal.  There's no reason not to insist
that the helper functions have names distinct from anything
used in the class or its bases.

>
>    If the private method didn't have to be declared in the interface,
>    you could have, effectively, two methods with the same signature
>    in effect at one in the class:  an inherited, non-private method
>    that remains accessible to classes derived from this one, and an
>    unrelated private method.
>
>    [I must admit I didn't think of this on my own.  Credit to
>    ARK & BEM, where credit is due.]

 Thanks to ARK and BEM. I know who Ark is, who is BEM?

>2.  The suggestion for non-virtual private methods could (I suspect)
>    be extended to private static data members, that is, that a
>    private static data member need not be declared in the class
>    interface.

 Yes.  You could also have private static fuctions too.
The syntax would be weird:

 class X { ..};
 namespace X {
  void func(); // non-static member
  int x; // not allowed
  static int x; // static data member
  static func(); // static function member
 };

The static members still have the usual external linkage.

>A question:  Should it be possible to somehow declare or forward declare
>a private method (or, if suggestion 2 is taken, private static data)
>which is not declared in the class header?

 Sure, see above.

>I would like to think not,

 Why?

>but this seems to be adding a limitation that currently doesn't exist
>in either C or C++ (eg. to mutually recursive routines).
>

 Private helpers for class X cannot access private
helpers for class Y. If you need that, you have to make
them declared private members.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: harrison@sp10.csrd.uiuc.edu (Luddy Harrison)
Date: Wed, 22 Dec 93 22:03:07 GMT
Raw View
It strikes me that John Max Skaller's proposal
to permit private, non-virtual
member functions to be omitted from a class declaration
goes only a small way toward hiding the implementation
of a class.  Often what gives me the greatest problem
in providing an interface is the private data members.
That is, I have a situation like this:

 class A { private: X x; Y y; public: A(); ... }

and I am forced to give the declarations of X and Y
(in the form of additional header files) to the user
that would like to make use of class A.

Add to this that private virtual functions would
still be required to be declared, and I think that this
proposal adds yet more complexity to the language with
too little in return.  There needs badly to be a separation
between implementation and interface, and to be a sensible
solution the separation must pertain to data members
and virtual functions, as well as private member functions.

Of course, template classes add another dimension to the
problem of providing an interface without exposing an
implementation.  If a library provides template classes, it
must provide declarations as well as definitions of
all of the member functions, virtual or otherwise.  If
template classes constitute any appreciable fraction of
an interface, then the band-aid of allowing private, non-virtual
member functions to be omitted is seen to be even less
satisfactory as a solution to the general problem.

-Luddy Harrison




Author: konigsba@cambridge.mitchell.com (Dan Konigsbach)
Date: 17 Dec 93 23:24:33 GMT
Raw View
On the topic of allowing private, non-virtual functions not to be included
in a class header...

maxtal@physics.su.OZ.AU (John Max Skaller) writes:

[Stuff deleted]

> Easy. Private helper are not allowed to be virtual.
>A private virtual is very much part of the interface.

> The proposal definitely works and has a number
>of advantages. It has a single disadvantage: it hides
>implementation details, in particular, it hides the
>names of all the functions that can get at the private
>data of the class. So you cant tell what the
>complete list of such functions is by a linear
>search of the class interface, instead you have
>to perform recursive descent on the definitions
>of the declared members.

> My thoughts on this are: so what. But others
>do not agree that hiding implementation details are as
>important, and without consensus the committee cannot
>pass the resolution.

I think that hiding the details of the implementation is a great
benefit.

-  A private method might need a declaration that the rest of the
   interface doesn't.  (For example, it might return something by
   value that only appears by pointer or by reference in the rest
   of the class interface.)  That declaration needs to be included
   by all class clients.  This widens the class interface in a way
   that I would consider unnecessary cohesion.

-  A change to the internal implementation (eg. breaking out the
   logic in a private method into additional private methods)
   requires a change to the interface.

Both of these examples have the practical annoyance of requiring
more frequent or longer makes than if the private implementation
could be hidden.

I apologize if these were discussed earlier in the thread, but
just in case not, here are two points to consider:

1.  If a private method has the same signature as a non-private
    method of a base class, then this BOTH declares the private
    method AND changes the accessibility of the name.

    If the private method didn't have to be declared in the interface,
    you could have, effectively, two methods with the same signature
    in effect at one in the class:  an inherited, non-private method
    that remains accessible to classes derived from this one, and an
    unrelated private method.

    [I must admit I didn't think of this on my own.  Credit to
    ARK & BEM, where credit is due.]

    I suggest that the private method should hide the inherited method
    from (roughly) the point it is encountered to the end of the
    compilation unit, except that, WHETHER OR NOT IT HAS BEEN ENCOUNTERD
    it has NO IMPACT WHATSOEVER on inheritance from this class.
    (Yes, I agree that, if it has not been encountered, it can't
    have an effect.  The suggestion is that this be the defined
    operation, not an abberation.  Sorta like declaring victory
    and leaving.)

2.  The suggestion for non-virtual private methods could (I suspect)
    be extended to private static data members, that is, that a
    private static data member need not be declared in the class
    interface.

A question:  Should it be possible to somehow declare or forward declare
a private method (or, if suggestion 2 is taken, private static data)
which is not declared in the class header?  I would like to think not,
but this seems to be adding a limitation that currently doesn't exist
in either C or C++ (eg. to mutually recursive routines).





Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: 9 Dec 93 18:41:40 GMT
Raw View
In article <nagleCHn1sF.11L@netcom.com> nagle@netcom.com (John Nagle) writes:
>maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>>OK, so what if there is a rule that if you use the namespace
>>thingy, there can only be ONE of them. Then all the definitions
>>and the helper functions as well must be in the one translation
>>unit, and in between the { } of the namespace at that.
>
>>In other words in this case the class definition must occur
>>in a single 'module', and can't be spread around.
>
>
>      Actually, being able to declare private function members of any
>class anywhere doesn't seem to open up any holes.  Only other private
>functions, and functions defined in the class header, could call them, right?
>So there's no new path into the interior of the class.  You could write
>private functions nobody can ever call, but that's harmless, and you can
>do it now.

 Of course. I wouldnt have proposed an extension that didnt work :-)

>      So, if the linker and V-table problems can be resolved, there's
>no reason to require that private functions be declared in the class header.

 Easy. Private helper are not allowed to be virtual.
A private virtual is very much part of the interface.

 The proposal definitely works and has a number
of advantages. It has a single disadvantage: it hides
implementation details, in particular, it hides the
names of all the functions that can get at the private
data of the class. So you cant tell what the
complete list of such functions is by a linear
search of the class interface, instead you have
to perform recursive descent on the definitions
of the declared members.

 My thoughts on this are: so what. But others
do not agree that hiding implementation details are as
important, and without consensus the committee cannot
pass the resolution.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA




Author: nagle@netcom.com (John Nagle)
Date: Tue, 7 Dec 1993 00:09:50 GMT
Raw View
maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>OK, so what if there is a rule that if you use the namespace
>thingy, there can only be ONE of them. Then all the definitions
>and the helper functions as well must be in the one translation
>unit, and in between the { } of the namespace at that.

>In other words in this case the class definition must occur
>in a single 'module', and can't be spread around.

      That would work, but some compilers have problems with
arbitrarily large compilation units.

      Actually, being able to declare private function members of any
class anywhere doesn't seem to open up any holes.  Only other private
functions, and functions defined in the class header, could call them, right?
So there's no new path into the interior of the class.  You could write
private functions nobody can ever call, but that's harmless, and you can
do it now.

      So, if the linker and V-table problems can be resolved, there's
no reason to require that private functions be declared in the class header.

     John Nagle