Friday, June 26, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 8 topics

JiiPee <no@notvalid.com>: Jun 26 09:18PM +0100

Everybody knows that with diamond inheritance we need virtual
inheritance. But what does virtual inheritance do really (for one
class)? like if i have:
 
class A
{
public:
int data;
};
 
class B : virtual public A
{
public:
int data2;
};
 
class C : public B
{};
 
So what difference "virtual" makes here to class B? if I take virtual
off what would be the difference than if I leave it there?
 
No books/tutorials seem to explain this, they only explain the diamond
formation.
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jun 26 10:35PM +0200

On 26.06.15 22.18, JiiPee wrote:
> {};
 
> So what difference "virtual" makes here to class B? if I take virtual
> off what would be the difference than if I leave it there?
 
In your example it makes no semantic difference, because there is no
multiple inheritance. But this may change if you derive from B and A.
 
Only if the class tree contains more than one A base, then virtual will
force them to share one instance of A. If there is only one link to A it
make no difference, of course.
 
> No books/tutorials seem to explain this, they only explain the diamond
> formation.
 
Well, there is no much to explain. Except there is a small runtime
overhead of virtual when accessing instance members of A.
 
 
Marcel
ram@zedat.fu-berlin.de (Stefan Ram): Jun 26 01:24PM

>and the ones that return nothing feels to be not about return
>type but about fact that the lack of return means that it *must*
>have side effect by other means to be not worthless.
 
That is not always so. For example, think of a printer
framework that requires a callback to be invoked right
before printing a page. So you open the framework with
 
FRAMEWORK framework = new_framework( callback );
 
. Incidentally, this time, you do not want additional action
done before a page is being printed. So, you define:
 
void callback() {}
 
. This function has no return value and no effect
(what you call »side effect«), yet it's perfectly
worthwhile. It tells the framework that nothing has
to be done before printing a page.
 
>subtype of ones that return something but in programming
>logic it feels as upside down like thinking of statements as
>subtype of expressions.
 
In C++, there is no statement that is an expression and
vice-versa.
 
Processors have operations that have pre- and
post-conditions. Higher programming languages usually try to
fit some of this into algebraic notation, especially the
mathematical notation of function application (therefore,
»FORTRAN« = »formula translator«), but there are some
mismatches between these two models.
ram@zedat.fu-berlin.de (Stefan Ram): Jun 26 04:47PM

>In modern C++ macros are a sign of noobishness and should be avoided.
 
I am a noobie, so I recently wrote this code for a
mathematical newsgroup which /has a macro/.
 
A person said that there was a »MatMate« where one can write:
 
prod({1,2}'+{3,4,5})
 
This will transform {1,2} to a column vector, add it to
{3,4,5}, which gives
 
1+3 1+4 1+5
2+3 2+4 2+5
 
and then »prod« will give
 
(1+3)×(1+4)×(1+5)×(2+3)×(2+4)×(2+5)
 
which will finally yield
 
25200
 
. I was so angry and upset! Could it be possible that an
largely unknown programming language called »MatMate« could
do something that my preferred language C++ cannot do? No!
This just can't be! I was determined to show that C++ can
do the same or better:
 
#include <iostream>
#include <ostream>
#include <vector>
 
int main()
{ ::std::cout << prod( COL{ 1, 2 }+ ROW{ 3, 4, 5 })<< '\n'; }
 
prints:
 
25200
 
I wrote the following definitions to implemente »prod«,
»COL«, »+« and »ROW«. The definitions are to be inserted
into the program above, above the main method. But I used a
macro!
 
#define MAKE(S,s) \
template< typename T >struct s : public ::std::vector< T > \
{ using ::std::vector< T >::vector; }; using S = s< double >;
MAKE( COL, col ) MAKE( ROW, row ) MAKE( MAT, mat )
template< typename T >auto operator +( col< T >c, row< T >r )
{ mat< T >m; for( auto x : c )for( auto y : r )
m.push_back( x + y ); return m; }
template< typename T > auto prod( mat< T >const m )
{ T r{ 1.0 }; for( auto x : m )r *= x; return r; }
 
The types »col«, »row«, »mat« are just vectors, but for type
recognizability, they need to be three different types, so
that these three kinds of vectors can be distinguished in
the C++ type systems. The uppercase variants are
conveniences for vectors of double values.
 
Ok, it might be possible to remove the macro definition, but
then the code would become longer and contain repeated code
patterns!
 
template< typename T >struct col : public ::std::vector< T > \
{ using ::std::vector< T >::vector; }; using COL = col< double >;
template< typename T >struct row : public ::std::vector< T > \
{ using ::std::vector< T >::vector; }; using ROW = row< double >;
template< typename T >struct mat : public ::std::vector< T > \
{ using ::std::vector< T >::vector; }; using MAT = mat< double >;
template< typename T >auto operator +( col< T >c, row< T >r )
{ mat< T >m; for( auto x : c )for( auto y : r )
m.push_back( x + y ); return m; }
template< typename T > auto prod( mat< T >const m )
{ T r{ 1.0 }; for( auto x : m )r *= x; return r; }
 
Such repetitions of code patterns reduce maintainability!
 
Can you rewrite the code so that it does not use a macro
but still has no repeated code patterns?
 
What is worse: The use of a macro or the use of repetitions?
ram@zedat.fu-berlin.de (Stefan Ram): Jun 26 08:35PM

>Everybody knows that with diamond inheritance we need virtual
>inheritance. But what does virtual inheritance do really (for one
>class)? like if i have:
 
I have no prior knowledge about »virtual inheritance«.
But from what I can read, the following sentences apply:
 
»For each distinct base class that is specified virtual,
the most derived object shall contain a single base
class subobject of that type.«
 
»For each distinct occurrence of a non-virtual base class
in the class lattice of the most derived class, the most
derived object shall contain a corresponding distinct
base class subobject of that type.«
 
 
>So what difference "virtual" makes here to class B? if I take
>virtual off what would be the difference than if I leave it
>there?
 
In C, there is one instance of C, one instance of B and
one instance of A.
 
In B, there is one instance of B and one instance of A.
 
In A, there is one instance of A.
 
Since all classes only ever contain /one/ instance of a
given class, the distinction between containing a /single/
base class subobject of that type and containing a
corresponding distinct base class subobject /for each/
distinct occurrence of a non-virtual base class does not
really apply here. So, in this case, the meaning should be
as if:
 
>class A
>class B : public A
>class C : public B
 
This might change, when there are additional classes (not
given here) that are related to the classes given here.
 
If a complete object, a data member, or an array element is
of class type, its type is considered the most derived
class, to distinguish it from the class type of any base
class subobject; an object of a most derived class type or
of a non-class type is called a most derived object.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 26 08:39PM +0100

... #include <cstdint> instead!
 
/Flibble
JiiPee <no@notvalid.com>: Jun 26 09:31PM +0100

On 26/06/2015 20:39, Mr Flibble wrote:
> ... #include <cstdint> instead!
 
> /Flibble
 
you mean using int16_t? why is that?
int is the fastest integer so why would i use something else?
"Öö Tiib" <ootiib@hot.ee>: Jun 26 02:22AM -0700

On Thursday, 25 June 2015 16:42:02 UTC+3, Stefan Ram wrote:
> terminology as a common language. After all, that's where
> »procedure« comes from AFAIK. What will be in some decades
> when programmers do not learn Pascal or Algol anymore?
 
That family isn't entirely dead. Delphi and Ada are pretty much
among alive languages; one can find a well-paid job of using
those. Other programming languages (like Visual Basic) make
similarly clear distinction.
 
> Could it be that for future children we will explain:
> »What's a procedure? It's just a function returning void!«
 
The difference between subprograms that return something
and the ones that return nothing feels to be not about return
type but about fact that the lack of return means that it *must*
have side effect by other means to be not worthless.
 
Technically subprograms that return nothing are indeed
subtype of ones that return something but in programming
logic it feels as upside down like thinking of statements as
subtype of expressions.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 26 11:50AM +0100

On Fri, 26 Jun 2015 02:22:46 -0700 (PDT)
Öö Tiib <ootiib@hot.ee> wrote:
[snip]
> subtype of ones that return something but in programming
> logic it feels as upside down like thinking of statements as
> subtype of expressions.
 
If this distinction between "procedure" and "function" is to have any
logic, the word "function" should be applied to functions which are
referentially transparent and so analogous to mathematical functions
and "procedure" to those which are intended to have side effects.
 
Take the case of a function which returns a boolean value to indicate
whether its side effects succeeded or not (a common idiom in C based
languages). It is conceptually indistinguishable from a function which
returns void and transmits success or failure in some other way, such as
by exceptions in C++.
 
This distinction seems to come from early languages for batch
processing. Most modern languages intended to provide some support for
composability (ie all of them) don't bother to try making a distinction,
nor do early functional languages such as lisp (indeed I am pretty
certain that the Structure and Interpretation of Computer Languages
applies "function" only to mathematical functions and "procedure" to
their practical expression in computer code - in any event "procedure"
is the universally applied term in lisps). C++ certainly doesn't make a
distinction.
 
Chris
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 26 11:55AM +0100

On Fri, 26 Jun 2015 11:50:59 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> Structure and Interpretation of Computer Languages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Structure and Interpretation of Computer Programs. My bad.
 
Chris
alf.p.steinbach@gmail.com: Jun 26 08:17AM -0700

On Friday, June 26, 2015 at 3:24:34 PM UTC+2, Stefan Ram wrote:
> (what you call »side effect«), yet it's perfectly
> worthwhile. It tells the framework that nothing has
> to be done before printing a page.
 
This is IMO a good observation, but only as a "do note that there are some exceptions" observation to novice readers. Öö Tiib is very well aware of dummy procedures, as am I, and indeed as any competent C++ programmer is, but in a debate, as opposed to when writing a textbook (say), pointing out all kinds of details that a novice might be unaware of is generally counter-productive, and might even be construed as condescending or patronizing. I am sure that the assumption that everybody would understand, is why it wasn't mentioned.
 
A perhaps more interesting example than a dummy callback, is a procedure used only for formal ODR "use" of its arguments, like this:
 
// With Visual C++ use "/W4", with g++ use "-Wall -Wextra".
template< class... Args >
void intentionally_unused( Args&&... ) {}
 
struct Base
{
virtual void foo( int n, char const* const id = "<no id>" ) const
 
#ifdef NO_WARNING
{ intentionally_unused( n, id ); } // A do-nothing default impl.
#else
{} // A do-nothing default impl.

No comments: