Small contribution to readability (of at least my code)

274 views
Skip to first unread message

John Yates

unread,
Nov 14, 2015, 2:14:08 PM11/14/15
to std-pr...@isocpp.org
I attempt to have one class per header.  This allows me to follow a file-wide organizing principle.

(This description will sidestep my treatment of a protected interface.)

The top of my class enumerates only the public interface (primarily method declarations).  I never include any (inline) method bodies.  Once done with the public interface I place an 80 character ////... boundary mark to indicate that beyond that point one will find only private members and method definitions.  For example

--- MyClass.hpp ---

#pragma once
#include "incl1.hpp"
#include "incl2.hpp"

class MyClass
  /// Doxygen markup positionally associated with MyClass...
{
public:
  MyClass(int =0);

  int val() const;
  void val(int);

////////////////////////////////////////////////////////////////////////////////
private:
  int val_;       ///< Doxygen markup positionally associated with data member...

};  // end of MyClass

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

inline
MyClass::MyClass
  /// Doxygen markup positionally associated with constructor...
  ( int val
  )
  : val_(val)
{}

inline
int MyClass::val
  /// Doxygen markup positionally associated with method...
  () const
{
  return val_;
}

inline
void MyClass::val
  /// Doxygen markup positionally associated with method...
  ( int val       ///< Doxygen markup positionally associated with parameter...
  )
{
  val_ = val;
}

-------------

While this style is textually longer it has a number of benefits.  Clearly the public interface is presented in a form that is very easy to consult once one is familiar with the class.  Often it is even a nearly ideal presentation even for ones first exposure.

If you believe as I do that the part of the gradual movement towards left-to-right declarations is a recognition that a name should be introduced before being described then you will understand my philosophy of Doxygen markup.  It always follows the name being documented.  This works at a human level because it is usually easy to spot the name being introduced.

Finally, apart for the preceding inline token,  the formatting of methods at the bottom of the header is identical to the formatting that I employ in the corresponding implementation file.  This makes moving a method between header and implementation truly nothing more than cut and paste (and of course deleting the orphaned inline token).

Sadly a number of these virtues diminish when the class is templatized:

--- MyTemplateClass.hpp ---

#pragma once
#include "incl1.hpp"
#include "incl2.hpp"

template<typename TYPE1, typename TYPE2>
class MyTemplateClass
  /// Doxygen markup positionally associated with MyTemplateClass...
{
public:
  MyTemplateClass(int =0);

  int val() const;
  void val(int);

////////////////////////////////////////////////////////////////////////////////
private:
  int val_;       ///< Doxygen markup positionally associated with data member...

};  // end of MyTemplateClass

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

template<typename TYPE1, typename TYPE2>
inline
MyTemplateClass<TYPE1, TYPE2>::MyTemplateClass
  /// Doxygen markup positionally associated with constructor...
  ( int val
  )
  : val_(val)
{}

template<typename TYPE1, typename TYPE2>
inline
int MyTemplateClass<TYPE1, TYPE2>::val
  /// Doxygen markup positionally associated with method...
  () const
{
  return val_;
}

template<typename TYPE1, typename TYPE2>
inline
void MyTemplateClass<TYPE1, TYPE2>::val
  /// Doxygen markup positionally associated with method...
  ( int val       ///< Doxygen markup positionally associated with parameter...
  )
{
  val_ = val;
}

-------------

Now the cost of separating method declaration at the top of the class from definition further down is a tougher sell.  Spotting the method name within the template baggage is less easy.  And there is no implementation .cpp file to which definitions might potentially get moved.

A possible solution occurred to me when I recently had cause to write the following:

class C {
public:
  struct S;
  struct S { int a; };
};

That is a type declared forward within a class can be resolved within that class.  So why can we not allow the same thing for methods:

template<typename TYPE1, typename TYPE2>
class MyTemplateClass
  /// Doxygen markup positionally associated with MyTemplateClass...
{
public:
  MyTemplateClass(int =0);

  int val() const;
  void val(int);

////////////////////////////////////////////////////////////////////////////////
private:
  int val_;       ///< Doxygen markup positionally associated with data member...

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  MyTemplateClass
    /// Doxygen markup positionally associated with constructor...
    ( int val
    )
    : val_(val)
  {}

  int val
    /// Doxygen markup positionally associated with method...
    () const
  {
    return val_;
  }

  void val
    /// Doxygen markup positionally associated with method...
    ( int val       ///< Doxygen markup positionally associated with parameter...
    )
  {
    val_ = val;
  }

};  // end of MyTemplateClass


If I could write that I probably would do it everywhere.

/john

Larry Evans

unread,
Nov 14, 2015, 4:43:17 PM11/14/15
to std-pr...@isocpp.org
On 11/14/2015 01:14 PM, John Yates wrote:
> I attempt to have one class per header. This allows me to follow a
> file-wide organizing principle.
>
Hi John,

I'd guess This topic is better covered in other newsgroups.
Try googling "c++.moderated coding style" to find a better
place to post you message.

BTW, I like your idea:

a name should be introduced before being described

which is a rule I use.

-regards,
Larry



Tony V E

unread,
Nov 14, 2015, 4:51:04 PM11/14/15
to Larry Evans
No if you read through the whole thing, I think you will find a proposal there. 

Basically, he wants to declare a member function, then later define it, *all within the class definition*

ie

class Foo {
public:
    int func();

//... 
private:
//...
    Int func() { return 17; }
};

Which might help particularly with templates. 

I think the private/public might be a problem. I would expect from compiler error about redeclaration. But if you switched back to public, I'd be OK with that.


Sent from my BlackBerry portable Babbage Device
  Original Message  
From: Larry Evans
Sent: Saturday, November 14, 2015 4:43 PM
To: std-pr...@isocpp.org
Reply To: std-pr...@isocpp.org
Subject: [std-proposals] Re: Small contribution to readability (of at least my code)
--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

John Yates

unread,
Nov 14, 2015, 4:57:22 PM11/14/15
to std-pr...@isocpp.org
Hi Larry,

Thanks for the reply.  I posted to this list because my proposal is not a request for help but rather a suggestion for a (small) language change.  It adds no functionality so my note attempted to show how it might improve the presentation of source.  Apparently I failed to convey that clearly enough in my previous post.

In the following only the declaration followed by definition within a class scope is disallowed:

// global scope
struct S;
struct S { int i; };
int f();
int f() { return 0; }  // OK

// within a namespace scope
namespace N {
  struct S;
  struct S { int i; };
  int f();
  int f() { return 0; }  // OK
}

// within a class scope
class C {
  struct S;
  struct S { int i; };
  int f();
  int f() { return 0; }  // ERROR!
};

I am proposing to allow that last case.

/john


Andrew Tomazos

unread,
Nov 15, 2015, 5:24:10 AM11/15/15
to std-pr...@isocpp.org
I think there is a good idea in here.

Rather than making this narrow change, I'd prefer to see a larger proposal for allowing a separate forward declaration of the public interface of a class from the definition of the class.

Perhaps something like:

public class MyClass {
  MyClass(int = 0);

  int val() const;
  void val(int);
};

class MyClass {
public:
  MyClass(int = 0) { ... }

  int val() const { ... }
  void val(int) { ... }

private:
  int val_;
};

The compiler would check that the public interface forward declaration matches the later class definition.  Consequently a human reader of the header file only needs to read the public interface declaration, and isn't distracted by implementation details, like inline function bodies and the private section.  The interface documentation comments could be placed on this forward declared public interface.

This is motivated by separating out interface specification from implementation specification, which are fundamentally separate design activities in software engineering.



John Yates

unread,
Nov 15, 2015, 9:41:51 AM11/15/15
to std-pr...@isocpp.org
On Sat, Nov 14, 2015 at 4:51 PM, Tony V E <tvan...@gmail.com> wrote:
I think the private/public might be a problem. I would expect from compiler error about redeclaration. But if you switched back to public, I'd be OK with that.

Indeed.  After experimenting with the following fragment I conclude that requiring consistent access is current behavior. 

class C {
// public introduction, definition in private section
public:
  struct Public;
private:
  struct Public { int i; };  // Error: redeclared with different access

// private introduction, definition in public section
private:
  struct Private;
public:
  struct Private { int i; };  // Error: redeclared with different access
};

/john

John Yates

unread,
Nov 15, 2015, 9:50:29 AM11/15/15
to std-pr...@isocpp.org
On Sun, Nov 15, 2015 at 5:24 AM, Andrew Tomazos <andrew...@gmail.com> wrote:
I'd prefer to see a larger proposal for allowing a separate forward declaration of the public interface of a class from the definition of the class.

My proposal feels like a very minor tweak to regularizes a small corner of the language.  Given some mentoring I am willing to take a crack at turning the suggestion into an official proposal.

I lack both the expertise and the bandwidth to develop such a more ambitious proposal.

Sure, a true concept of interfaces in C++ might be nice but I am loath to allow "better to be the enemy of good.".  My small suggestion addresses my personal itch.

/john


Nicol Bolas

unread,
Nov 15, 2015, 10:05:57 AM11/15/15
to ISO C++ Standard - Future Proposals, jo...@yates-sheets.org
On Saturday, November 14, 2015 at 2:14:08 PM UTC-5, John Yates wrote:
If you believe as I do that the part of the gradual movement towards left-to-right declarations is a recognition that a name should be introduced before being described then you will understand my philosophy of Doxygen markup.

Here's my feeling on this.

Normally in C++, you aren't allowed to talk about a name before it gets used. If a name appears later in a file, too bad; you have to forward declare it or you get a compiler error.

This is true everywhere... except in a class definition. There, you are allowed to talk about names that appear later in the class. This was specifically added to the language, because nowhere else does the language work this way. Adding this feature made compilers rather more difficult to write. But it makes code much easier to write, since you don't have to declare every member before writing the definitions of those member functions. Not to mention, it makes things like CRTP-mixins possible, where a base class can cast itself to the derived class type and access its members; that would not be possible if C++ didn't allow delayed name lookup.

In short, it is a very good thing that C++ allows this.

My feeling is that if you need to forward declare a member function, you ought to just define it outside of the class definition. Yes, I know that this makes it rather difficult for template classes, due to the gigantic prefix associated with the function name. But we have C++ tools for creating member function definitions automatically nowadays. It's not that big of a deal.

Ville Voutilainen

unread,
Nov 15, 2015, 10:23:40 AM11/15/15
to ISO C++ Standard - Future Proposals
On 15 November 2015 at 17:05, Nicol Bolas <jmck...@gmail.com> wrote:
> Here's my feeling on this.
>
> Normally in C++, you aren't allowed to talk about a name before it gets
> used. If a name appears later in a file, too bad; you have to forward
> declare it or you get a compiler error.
>
> This is true everywhere... except in a class definition. There, you are
> allowed to talk about names that appear later in the class. This was
> specifically added to the language, because nowhere else does the language
> work this way. Adding this feature made compilers rather more difficult to
> write. But it makes code much easier to write, since you don't have to
> declare every member before writing the definitions of those member
> functions. Not to mention, it makes things like CRTP-mixins possible, where
> a base class can cast itself to the derived class type and access its
> members; that would not be possible if C++ didn't allow delayed name lookup.
>
> In short, it is a very good thing that C++ allows this.

Being able to declare member functions multiple times would not change that.

However, allowing multiple declarations increases implementation complexity.
This case is fairly easy:

struct X
{
X();
X();
};

as is this case:

struct X
{
X();
X() {}
};

this case adds complexity:

struct X
{
X();
X() = default;
};

Now, presumably, the in-class-definition default is to be handled the same way
as a defaulted definition outside the class definition. The icky part of that is
that the meaning of such a defaulted definition depends on whether there was
a previous declaration or not. That hurts code readability and being able to
reason about in-class defaulted definitions. In case some wonder whether
the meaning should be as it is for an in-class defaulted definition, then the
meaning of the first declaration depends on whether there's a
defaulted definition
later in the class definition.

Regarding the "easy cases" I mentioned, currently, gcc for instance diagnoses
completely identical overloads with the same code as it uses to
diagnose overloads
that have identical parameters but different return types. That does also mean
that it doesn't even try to check whether two identical declarations
in a class have
identical definitions; it doesn't need to, because it will reject the
overload. Consider:

struct X
{
X() {}
X() {} // should this be allowed? Should it be checked that the
definitions are identical?
};

None of these problems are insurmountable, but the motivation for
allowing multiple
identical declarations inside a class definition seems weak. I'd
expect very few programmers
to use it, and while the added implementation complexity isn't
necessarily huge, the
cost/benefit ratio doesn't seem to be very good.

Matthew Woehlke

unread,
Nov 16, 2015, 10:13:30 AM11/16/15
to std-pr...@isocpp.org
On 2015-11-15 05:24, Andrew Tomazos wrote:
> I think there is a good idea in here.
>
> Rather than making this narrow change, I'd prefer to see a larger proposal
> for allowing a separate forward declaration of the public interface of a
> class from the definition of the class.
>
> Perhaps something like:
>
> public class MyClass {
> MyClass(int = 0);
>
> int val() const;
> void val(int);
> };
>
> class MyClass {
> public:
> MyClass(int = 0) { ... }
>
> int val() const { ... }
> void val(int) { ... }
>
> private:
> int val_;
> };

I don't think this will work. The size of the class needs to be known
publicly. Adding NSDM's after the fact will break things. (And adding
any other members opens a can of worms to abuse / circumvention of
access protections.)

That said, my first thought reading through the OP's post was to have a
way to provide method definitions that doesn't require repeating the
class name (and template) boiler plate. Something closer to a namespace
block might be better for this purpose. Ideally, access statements would
be forbidden (and unnecessary) in this context, and only definitions of
previously declared members would be allowed. IOW, a way to turn this:

A::A() { ... }
int A::foo(int) { ... }
int A::bar = ...;

...into this:

<block scope for A> {
A() { ... }
int foo(int) { ... }
int bar = ...;
}

The syntax for introducing the block scope might be something like
'template<typename T> class namespace Bar<T>' (template example given
for completeness; omit template stuff for non-template classes).

This is a syntax change, but NOT a semantic change; just like a
namespace, the effect is simply as if everything in the scope is
implicitly prefixed with the class decoration.

(Say, wasn't there a request for template block scopes already?)

--
Matthew

Andrew Tomazos

unread,
Nov 16, 2015, 11:59:30 AM11/16/15
to std-pr...@isocpp.org
On Mon, Nov 16, 2015 at 4:13 PM, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
On 2015-11-15 05:24, Andrew Tomazos wrote:
> I think there is a good idea in here.
>
> Rather than making this narrow change, I'd prefer to see a larger proposal
> for allowing a separate forward declaration of the public interface of a
> class from the definition of the class.
>
> Perhaps something like:
>
> public class MyClass {
>   MyClass(int = 0);
>
>   int val() const;
>   void val(int);
> };
>
> class MyClass {
> public:
>   MyClass(int = 0) { ... }
>
>   int val() const { ... }
>   void val(int) { ... }
>
> private:
>   int val_;
> };

I don't think this will work. The size of the class needs to be known
publicly. Adding NSDM's after the fact will break things. (And adding
any other members opens a can of worms to abuse / circumvention of
access protections.)

You've misunderstood how it works.  The class isn't complete (as usual) until the class definition (the second thing).  The forward declaration of the public interface doesn't complete the class type.  You still need the definition.  You can't do anything with the public interface declaration alone.

You can think of it as a compiler-checked description of the public interface of the class.  The class definition then describes how the class is implemented.  This is similar to the relationship between, say, a template declaration and a template definition.  Yes, both (usually) need to be in the header file.

Matthew Woehlke

unread,
Nov 16, 2015, 12:19:42 PM11/16/15
to std-pr...@isocpp.org
On 2015-11-16 11:59, Andrew Tomazos wrote:
> On Mon, Nov 16, 2015 at 4:13 PM, Matthew Woehlke wrote:
>> On 2015-11-15 05:24, Andrew Tomazos wrote:
>>> I think there is a good idea in here.
>>>
>>> Rather than making this narrow change, I'd prefer to see a larger
>>> proposal for allowing a separate forward declaration of the
>>> public interface of a class from the definition of the class.
>>>
>>> Perhaps something like:
>>>
>>> public class MyClass {
>>> MyClass(int = 0);
>>>
>>> int val() const;
>>> void val(int);
>>> };
>>>
>>> class MyClass {
>>> public:
>>> MyClass(int = 0) { ... }
>>>
>>> int val() const { ... }
>>> void val(int) { ... }
>>>
>>> private:
>>> int val_;
>>> };
>>
>> I don't think this will work. The size of the class needs to be known
>> publicly. Adding NSDM's after the fact will break things. (And adding
>> any other members opens a can of worms to abuse / circumvention of
>> access protections.)
>
> You've misunderstood how it works. The class isn't complete (as usual)
> until the class definition (the second thing).

Ah. Yes, I missed that. Okay, well then, I dislike it for other reasons.
Mainly, it does nothing to solve the redundancy when the method
definitions are not inline in the class definition (e.g. when they are
in a .cpp file). And yes, even for template classes, that can happen,
either ".tpp" pattern, or due to explicit instantiation.

In fact, I have trouble seeing how your suggestion is in any meaningful
way an improvement over what we have now. All you've really accomplished
is adding a closing brace before the private members. That may look
pretty, but it hardly seems worth a non-trivial change to both syntax
and semantics.

I much prefer my suggestion which does not change semantics, and
reflects existing syntax for namespaces.

--
Matthew

Andrew Tomazos

unread,
Nov 16, 2015, 1:58:32 PM11/16/15
to std-pr...@isocpp.org
I'm not sure what you mean by "solve the redundancy".  What redundancy?  If you mean the redundancy between an interface and implementation - that's a feature, not a bug.

In fact, I have trouble seeing how your suggestion is in any meaningful
way an improvement over what we have now. All you've really accomplished
is adding a closing brace before the private members. That may look
pretty, but it hardly seems worth a non-trivial change to both syntax
and semantics.
 
It doesn't change any semantics.  It's more than adding a closing brace before the private members.

In particular the forward declaration of the public interface wouldn't be permitted to contain any definitions, it's purely a declaration.

For example, take a look at any of the class definitions of the containers in any standard library implementation.

They are 1000+ lines long and even the public sections (plural) are 90% implementation details.

Having the public interface separately declared at the top of the file is better for the reader, as they don't need to wade through these implementation details to learn the interface.  Yes, it's more work for the writer to maintain this separate interface declaration.  As we should have all been taught at school the reader has priority, for many reasons.

Matthew Woehlke

unread,
Nov 16, 2015, 2:42:00 PM11/16/15
to std-pr...@isocpp.org
On 2015-11-16 13:58, Andrew Tomazos wrote:
> On Mon, Nov 16, 2015 at 6:19 PM, Matthew Woehlke wrote:
>> Mainly, it does nothing to solve the redundancy when the method
>> definitions are not inline in the class definition (e.g. when they are
>> in a .cpp file). And yes, even for template classes, that can happen,
>> either ".tpp" pattern, or due to explicit instantiation.
>
> I'm not sure what you mean by "solve the redundancy". What redundancy? If
> you mean the redundancy between an interface and implementation - that's a
> feature, not a bug.

template <...> class Foo { ...declarations... };
template <...> Foo<...>::Foo(...) { ... }

All that template boilerplate is annoying. This was a major point of the
OP's original suggestion (with which I happen to agree).

>> In fact, I have trouble seeing how your suggestion is in any meaningful
>> way an improvement over what we have now. All you've really accomplished
>> is adding a closing brace before the private members. That may look
>> pretty, but it hardly seems worth a non-trivial change to both syntax
>> and semantics.
>
> It's more than adding a closing brace before the private members.

In what way? I don't see how your feature adds anything (excluding
support for duplicate member declarations) except:

public // new
class Foo
{
// declarations of public methods
}; // new
class Foo // new
{ // new
// class definition
};

> In particular the forward declaration of the public interface wouldn't be
> permitted to contain any definitions, it's purely a declaration.
>
> It doesn't change any semantics.

That *is* a semantic change (at least, what I'm considering a semantic
change). You have added an entirely new concept ("class interface
declaration") with new semantics ("may not contain definitions").

My suggestion just hoists a bunch of prefix code to a block scope,
without changing what is legal within that scope. The *existence* of
said scope is arguably semantic (although it's equivalent to a namespace
scope, which is an existing construct), but the semantics of the scope
itself are not new.

> For example, take a look at any of the class definitions of the containers
> in any standard library implementation.
>
> They are 1000+ lines long and even the public sections (plural) are 90%
> implementation details.

And why do you expect your proposal to "fix" this? That problem exists
because library writers *don't care*. If they did, they would not have
inline definitions and would keep the class private and public members
separate. Both of which *can be done in C++03*. Why do you expect that
providing a new way to do something they aren't interested in is going
to help?

--
Matthew

Péter

unread,
Nov 17, 2015, 3:01:52 AM11/17/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
This has come up already in the "Fixing the private method issue" thread, my idea was pretty similar to yours (see https://groups.google.com/a/isocpp.org/d/msg/std-proposals/xukd1mgd21I/uHjx6YR_EnQJ and https://groups.google.com/a/isocpp.org/d/msg/std-proposals/xukd1mgd21I/gh5W0KS856oJ).  Unfortunately that got nowhere because it sorta got bogged down with the more ambitious goal of adding "real" private methods.  I'd be happy if the "class namespace" proposal would move forward either alone, or with the addition of extra private methods as discussed in the above thread.
 

Andrew Tomazos

unread,
Nov 17, 2015, 6:09:20 AM11/17/15
to std-pr...@isocpp.org

On Mon, Nov 16, 2015 at 8:41 PM, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
On 2015-11-16 13:58, Andrew Tomazos wrote:
> For example, take a look at any of the class definitions of the containers
> in any standard library implementation.
>
> They are 1000+ lines long and even the public sections (plural) are 90%
> implementation details.

And why do you expect your proposal to "fix" this? That problem exists
because library writers *don't care*. 
 
The current technique of defining members outside the class is onerous.  In particular you need to redeclare the enclosing class (and template) for each member defined.  Defining members inside the class definition is much easier because the enclosing class only needs to be declared once and is thereafter implicit for the scope.  By providing a way to separately declare the public interface, it allows library authors to continue to use the class definition to conveniantly define members inline - while enabling them to specify the public interface separately.

Given that it is less onerous, I expect it to be more popular than not using inline member definitions.

(Note by "member definitions" I am not only thinking about inline member functions.  I am also thinking about nested types, typedefs/aliases, member variable initializers and member templates.)

Matthew Woehlke

unread,
Nov 17, 2015, 10:48:49 AM11/17/15
to std-pr...@isocpp.org
On 2015-11-17 06:09, Andrew Tomazos wrote:
> On Mon, Nov 16, 2015 at 8:41 PM, Matthew Woehlke wrote:
>> On 2015-11-16 13:58, Andrew Tomazos wrote:
>>> For example, take a look at any of the class definitions of the
>>> containers in any standard library implementation.
>>>
>>> They are 1000+ lines long and even the public sections (plural) are 90%
>>> implementation details.
>>
>> And why do you expect your proposal to "fix" this? That problem exists
>> because library writers *don't care*.
>
> Defining members inside the class definition is much
> easier because the enclosing class only needs to be declared once and is
> thereafter implicit for the scope.

...but then you *must* provide definitions *in the header*. In
non-template cases, this is usually a very bad thing to do. Even in some
*template* cases it is undesirable. This makes your proposal of very
limited utility in the majority of cases.

> The current technique of defining members outside the class is onerous. In
> particular you need to redeclare the enclosing class (and template) for
> each member defined.

I agree the *current* situation is less than ideal, but did you *read*
my suggestion? Because this is *exactly* the problem I address...

That said, I still have doubts that standard libraries are going to
change. It may be onerous, but code is written once and read many times.
If standard library authors cared about readability, they would make the
effort, even if it is currently "onerous".

For that matter, there's nothing stopping anyone from doing exactly like
your proposal, only in a comment, right now. Again... *if* they cared.

> Given that it is less onerous, I expect it to be more popular than not
> using inline member definitions.

Or... my suggestion makes *non-inline* definitions, which *are the right
thing to do* more often than not, equally less onerous.

> (Note by "member definitions" I am not only thinking about inline member
> functions. I am also thinking about nested types, typedefs/aliases, member
> variable initializers and member templates.)

Nested types can be forward declared already. How many type aliases a)
do you *want* to be opaque, and b) have an RHS that is so long as to
cause readability problems if they appear in the "public interface
declaration"?

(You'll note I didn't mention member initializers, even though the
second half of the type alias argument applies here too. IMO it would be
nice, albeit probably an orthogonal feature, if NSDM initializers could
appear in a separate TU in the manner of SDM's. These would only be
effective for non-default ctors whose definitions follow said
initializers, but that shouldn't be a problem. Allowing this has similar
benefits to non-inline member function definitions.)

--
Matthew

Russell Greene

unread,
Nov 17, 2015, 11:22:37 AM11/17/15
to std-pr...@isocpp.org

One small issue I have with this is the current method lets you put includes that only the inline functions rely on after the class declaration. With this proposal this isn't possible.

The only way this case could work is with the "interface" idea:

public class MyClass {

  MyClass(int = 0);

  int val() const;

  void val(int);

};

// put includes here

class MyClass {

public:

  MyClass(int = 0) { ... }

  int val() const { ... }

  void val(int) { ... }

private:

  int val_;

};

Although I don't like that syntax. Not sure what would be best for that.


Matthew Woehlke

unread,
Nov 17, 2015, 11:55:10 AM11/17/15
to std-pr...@isocpp.org
On 2015-11-17 11:22, Russell Greene wrote:
> One small issue I have with this is the current method lets you put
> includes that only the inline functions rely on after the class
> declaration. With this proposal this isn't possible.

Why not? (Note: you said "function", specifically.)

This would be the case for type aliases (and member variable
initializers, although see my previous comment). It is *not* true for
method definitions or nested types, as neither of those need to appear
in the class definition (nor is there AFAIK any specific technical
benefit to having them inline).

Personally, I only *rarely* see includes other than at the top of a file
(and those usually in files that are a terrific mess of preprocessor
conditional logic).


Example:

class MyClass
{
public:
MyClass(int = 0);
int val() const;
void set_val(int);

private:
int m_val;
};

// place "private" includes here

namespace class MyClass
{
MyClass(int) { ... }
int val() const { ... }
void set_val(int) { ... }
}

--
Matthew

Evan Teran

unread,
Nov 17, 2015, 7:10:42 PM11/17/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

Example:

  class MyClass
  {
  public:
    MyClass(int = 0);
    int val() const;
    void set_val(int);

  private:
    int m_val;
  };

  // place "private" includes here

  namespace class MyClass
  {
    MyClass(int) { ... }
    int val() const { ... }
    void set_val(int) { ... }
  }
 

I think this new syntax idea potentially provides real benefit. I like it a lot. One the motivating pain points of templates is that if you separate declaration from definition, you have to deal with very verbose template syntax. For example:



template <class Ch, class Tr>
class String {
public:
   
void some_method();
   
void another_method();
};


template <class Ch, class Tr>
void String<Ch, Tr>::some_method() {
   
// ...
}

template <class Ch, class Tr>
void String<Ch, Tr>::another_method() {
   
// ...
}


If this could instead be written like the following code, then it would be simpler to read, write and maintain:

template <class Ch, class Tr>
class String {
public:
   
void some_method();
};


template <class Ch, class Tr>
namespace class String {

void some_method() {
   
// ...
}


void another_method() {
   
// ...
}
}

In my opinion this syntax or something similar to it, is:

1. easier to read, we get to drop the "noise" of the repeated template parameters, but it is still explicit enough to know what it means

2. easier to write, for single functions, there is a slight increase in code, but for a large group of functions, it can drastically reduce the amount of code while not sacrificing clarity.

3. easier to maintain, if a template parameter changes, we would need to change it far fewer places (two places instead of once per non-inline method)

Like I said, I would very much welcome this as as option as long as the previous syntax doesn't get removed :-).

Russell Greene

unread,
Nov 17, 2015, 11:11:51 PM11/17/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
I agree. This is a really good syntax, I was confused with the proposal before. 

I would really like to see this as I am creating a large library that has one very large template class, and currently I have the functions in the class declaration, which is sacrificing clarity. 

I don't really like the use of namespace in the syntax though. It makes it seem like it actually has to do with namespaces, which it doesn't.

-Russell

--

Larry Evans

unread,
Nov 18, 2015, 4:05:23 AM11/18/15
to std-pr...@isocpp.org
On 11/17/2015 10:11 PM, Russell Greene wrote:
> I agree. This is a really good syntax, I was confused with the proposal
> before.
>
> I would really like to see this as I am creating a large library that
> has one very large template class, and currently I have the functions in
> the class declaration, which is sacrificing clarity.
>
> I don't really like the use of namespace in the syntax though. It makes
> it seem like it actually has to do with namespaces, which
> it doesn't.

I think someone proposed use of public instead of namespace.
Would you prefer that?

I think people are just trying to avoid another keyword and
sacrificing a *little* readablity for that purpose.
> void String<Ch,Tr>::another_method(){
Yes! I welcome this syntax simplication also.

However, what about static members? For example:

template<classCh,classTr>
class String{
public:
String(classCh ch);//new
void some_method();

template<classCh Ch>
static strch;//new
};


template<classCh,classTr>
namespace class String{

String(classCh ch){
// ...
}

void some_method(){
// ...
}

void another_method(){
// ...
}

template<classCh Ch>
static strch(Ch);
};

Would this be allowed under this proposal?

-regards,
Larry


Larry Evans

unread,
Nov 18, 2015, 4:18:06 AM11/18/15
to std-pr...@isocpp.org
OOPS. Sorry for typos:
>
> template<classCh,classTr>
> class String{
> public:
> String(classCh ch);//new
> void some_method();
Should include:
void another_method();
>
> template<classCh Ch>
> static strch;//new
Should be:
static String strch;//new
> };
>
>
> template<classCh,classTr>
> namespace class String{
>
> String(classCh ch){
> // ...
> }
>
> void some_method(){
> // ...
> }
>
> void another_method(){
> // ...
> }
>
> template<classCh Ch>
> static strch(Ch);
Should be:
static String strch(Ch);

Evan Teran

unread,
Nov 18, 2015, 7:48:11 AM11/18/15
to ISO C++ Standard - Future Proposals, cpplj...@suddenlink.net
My suggestion is for something like:

template <class Ch, class Tr>
namespace class String {
void member() {}
}


to be exactly equivalent to:

template <class Ch, class Tr>
void String<Ch, Tr>::member() {}

So for the example of a static members, constructors, etc, this would continue to be equivalent, for example:


// typical class declaration

template <class Ch, class Tr>
class String {
public:

 
String(Ch ch);
 
void some_method();
 
void another_method();
 
static String strch(Ch ch);
};




// non-inline definition using proposed syntax

template<class Ch, class Tr>
namespace class String { /* I'm ok with any keyword besides "namespace" */


String(Ch ch) {
 
// ...
}


void some_method() {
 
// ...
}


void another_method() {
 
// ...
}


String strch(Ch) {
 
// ...
}


}


which would be the same as writing this code:

template <class Ch, class Tr>
String<Ch, Tr>::String(Ch ch) {
 
// ...
}


template <class Ch, class Tr>
void String<Ch, Tr>::some_method() {
 
// ...
}


template <class Ch, class Tr>
void String<Ch, Tr>::another_method() {
 
// ...
}


template <class Ch, class Tr>
String<Ch, Tr> String<Ch, Tr>::strch(Ch) {
 
// ...
}

Evan Teran

unread,
Nov 18, 2015, 7:58:53 AM11/18/15
to ISO C++ Standard - Future Proposals, cpplj...@suddenlink.net

Also, to be clear, members which have separate template parameters from the class are also covered cleanly:

template <class T>
class MyClass {
public:
   
template <class U>
   
void member(U u);
};


// current syntax (yuck)


template <class T> // did i get the ordering right, I always forget!
template <class U>
void MyClass<T>::member(U u) {
   
// ...
}


// proposed syntax, no room for mistakes, much clearer
template <class T>
namespace class MyClass {


template <class U>
void member(U u) {
   
// ..
}


}

Matthew Woehlke

unread,
Nov 18, 2015, 10:27:10 AM11/18/15
to std-pr...@isocpp.org
On 2015-11-17 19:10, Evan Teran wrote:
> Like I said, I would very much welcome this as as option as long as the
> previous syntax doesn't get removed :-).

Of course not :-). Besides compatibility, we allow this:

namespace Foo { int bar(); }
int Foo::bar() { ... }

It would be strange indeed to allow that but suddenly forbid explicitly
prefixed class methods :-).

On 2015-11-17 23:11, Russell Greene wrote:
> I agree. This is a really good syntax, I was confused with the proposal
> before.

Ah. Sorry for the confusion.

> I don't really like the use of namespace in the syntax though.

Sure. Syntax is open for discussion; I agree the "namespace class" is
potentially dubious (partly why I originally wrote "<block scope>"
rather than suggesting an actual syntax).

--
Matthew

Matthew Woehlke

unread,
Nov 18, 2015, 10:35:06 AM11/18/15
to std-pr...@isocpp.org
On 2015-11-18 04:17, Larry Evans wrote:
> However, what about static members? For example:
>
> template<classCh,classTr>
> class String{
> public:
> String(classCh ch);//new
> void some_method();
> void another_method();
>
> static String strch;//new
> };
>
>
> template<classCh,classTr>
> namespace class String{
>
> String(classCh ch){
> // ...
> }
>
> void some_method(){
> // ...
> }
>
> void another_method(){
> // ...
> }
>
> static String strch(Ch);
> };
>
> Would this be allowed under this proposal?

No, but only because your definition of strch wouldn't be legal with the
class name included.

This:

template <...> namespace class String
{
void some_method() { ... }
String<...> strch = ...; // see note
}

...is exactly the same as:

template <...> void String<...>::some_method() { ... }
template <...> String<...> String<...>::strch { ... }

That is, the effect of 'namespace template' is simply to transform all
declarations / definitions therein as if they were prefixed with the
[template args and] class name. Anything you can do with an explicit
prefix, you can do in a class namespace, likewise the converse and
inverse. Your above example is thus not permitted because "static" would
not be permitted in:

template <...>
static String<...> String<...>::strch = ...;

...and because you omitted the template arguments when naming the type.
The latter is a more interesting question; should any mention of the
type name implicitly have the template parameters of the scope? That
would be convenient, but we don't permit it currently. For simplicity,
I'm inclined to say "no", but a follow-up proposal could add that. (We
would still want to allow giving the template parameters in case they
would be different.)

--
Matthew

John Yates

unread,
Nov 18, 2015, 11:38:18 AM11/18/15
to std-pr...@isocpp.org
On Wed, Nov 18, 2015 at 10:26 AM, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
Sure. Syntax is open for discussion; I agree the "namespace class" is
potentially dubious (partly why I originally wrote "<block scope>"
rather than suggesting an actual syntax).

I think syntax of the form

<access> [ template <...> ] class <identifier> { ... };

is unambiguous.  It clearly calls out that this is something distinct from a class definition.  It factors out the painful naming and clearly defines the access so that current checks can continue to be enforced.  It has the somewhat geeky property that the 'factored' elements all appear ahead of the class token :-)

/john

Matthew Woehlke

unread,
Nov 19, 2015, 10:39:39 AM11/19/15
to std-pr...@isocpp.org
On 2015-11-18 11:38, John Yates wrote:
> On Wed, Nov 18, 2015 at 10:26 AM, Matthew Woehlke wrote:
>
>> Sure. Syntax is open for discussion; I agree the "namespace class" is
>> potentially dubious (partly why I originally wrote "<block scope>"
>> rather than suggesting an actual syntax).
>
> I think syntax of the form
>
> <access> [ template <...> ] class <identifier> { ... };
>
> is unambiguous.

Assuming you mean that as a syntax for my proposal, I don't like it. It
violates DRY (making you repeat the access specification), and requires
a separate scope block for each access level.

FWIW, I disagree that a class is not a namespace. I mean, obviously it's
not exactly a "namespace" (C++ keyword), but it is a name scope (i.e.
"name space" in colloquial English). Hence, I would read "namespace
class A" as:

- "namespace": I am about to provide declarations and/or definitions
that live in a particular name scope. To know what scope, I will keep
reading.

- "class": Ah... the name scope is a class, not a traditional
"namespace". (I also know that it will contain only definitions.) I
don't know what scope, yet... keep reading.

- "A": Ah... I will provide definitions that are in the scope of the
class named "A".

Again, some other keyword *might* be better (although to be honest I'm
having a hard time coming up with one... I don't like "with" or "scope"
all that much better).

--
Matthew

Evan Teran

unread,
Nov 19, 2015, 11:20:51 AM11/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

I agree with Matthew here about access specifier, I don't think it is useful (or simpler) to have a separate scope for each access type. As Matthew said, it's not a c++ namespace, but it is a namespace in the colloquial English sense, so it's not like it is complete nonsense.

Perhaps this would be a good place to re-use the now defunct export keyword or similar? (I would have actually favored "extern" more since the definition of of the functions are "external". But yea, generically something like this is what I would prefer.

[ template <...> ] <keyword> class <identifier> { ... }

I like template first, since that is consistent with other areas of the language. Also note, that I removed the semicolon at the end. This isn't declaring a class, it is defining methods of an already defined class. Similar to how namespace doesn't require the semicolon. That being said, the particular keyword we use to identify the construct is more of a minor concern, I would just want it to make "sense" since the goal is to increase readability. However, some things are like storage classes can be more or less immediately dismissed since they are already valid code:

static class A {} a;
extern class A{} a;
etc..

Evan Teran

unread,
Nov 19, 2015, 11:23:32 AM11/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

Another option would be to introduce a context sensitive keyword which strikes me as a lot more viable if we were to add a new one. For example (scope being the example):


template <...> class : scope <identifier> {}

Since currently a colon can't follow the class keyword here, it's a way to inject any identifier we wish without breaking existing code. Thoughts?

Nicol Bolas

unread,
Nov 19, 2015, 11:43:33 AM11/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com


On Thursday, November 19, 2015 at 11:20:51 AM UTC-5, Evan Teran wrote:

I agree with Matthew here about access specifier, I don't think it is useful (or simpler) to have a separate scope for each access type. As Matthew said, it's not a c++ namespace, but it is a namespace in the colloquial English sense, so it's not like it is complete nonsense.

So it's a `class namespace` rather than a "global" `namespace`. Maybe that should be handled syntactically:

template<blah>
class namespace >TypeName<
{
};
 
Perhaps this would be a good place to re-use the now defunct export keyword or similar? (I would have actually favored "extern" more since the definition of of the functions are "external". But yea, generically something like this is what I would prefer.

No, modules has dibs on `export`. And this feature, nice though it may be, is less important than modules ;)

Nicol Bolas

unread,
Nov 19, 2015, 11:47:28 AM11/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com


On Thursday, November 19, 2015 at 11:23:32 AM UTC-5, Evan Teran wrote:

Another option would be to introduce a context sensitive keyword which strikes me as a lot more viable if we were to add a new one. For example (scope being the example):


template <...> class : scope <identifier> {}

That is declaring an anonymous template class who's base class is `scope`. Which is perfectly legal to do today.

John Yates

unread,
Nov 19, 2015, 11:47:49 AM11/19/15
to std-pr...@isocpp.org, mwoehlk...@gmail.com
On Thu, Nov 19, 2015 at 11:20 AM, Evan Teran <evan....@gmail.com> wrote:
I agree with Matthew here about access specifier, I don't think it is useful (or simpler) to have a separate scope for each access type. As Matthew said, it's not a c++ namespace, but it is a namespace in the colloquial English sense, so it's not like it is complete nonsense.

Agreed.
 
Perhaps this would be a good place to re-use the now defunct export keyword or similar? (I would have actually favored "extern" more since the definition of of the functions are "external". But yea, generically something like this is what I would prefer.

[ template <...> ] <keyword> class <identifier> { ... }

I am comfortable with Matthew's defense of namespace being the appropriate value for <keyword>.
 
Also note, that I removed the semicolon at the end. This isn't declaring a class, it is defining methods of an already defined class. Similar to how namespace doesn't require the semicolon.

That make sense.  In the absence of a template prefix having the keyword namespace first should help newcomers understand that no semicolon is needed.  (I understand the "declarations get a semicolon, definitions get a block" logic.  But that it not how I have internalized the syntax.  To me it is simply aggregates get a semicolon, namespaces do not.  I suspect that I am not the lone simpleton :-)

/john

Evan Teran

unread,
Nov 19, 2015, 11:58:22 AM11/19/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
Damn, you are correct :-(. My bad, Never mind that suggestion.

John Yates

unread,
Nov 19, 2015, 2:13:56 PM11/19/15
to std-pr...@isocpp.org
On Thu, Nov 19, 2015 at 10:39 AM, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
Assuming you mean that as a syntax for my proposal, I don't like it. It
violates DRY (making you repeat the access specification), and requires
a separate scope block for each access level.

I am an ardent proponent of DRY so I am please to see you invoke
it as an argument against my suggestion.  Indeed I much prefer
not having to supply access.
 
FWIW, I disagree that a class is not a namespace. I mean, obviously it's
not exactly a "namespace" (C++ keyword), but it is a name scope (i.e.
"name space" in colloquial English).
 
I agree entirely.  My suggestion was merely a groping for a solution
that eschewed namespace while introducing no new keywords.

/john


Reply all
Reply to author
Forward
0 new messages