Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Some C++14 code

417 views
Skip to first unread message

Alf P. Steinbach

unread,
Jul 7, 2018, 10:27:49 PM7/7/18
to
I was baffled why I couldn't static_cast to ordinary reference in this
code, and then apply move(), rather than static_cast to rvalue
reference, doing the work of move() myself:

struct Sub
: Text_item
, Itemlist
{
template< class Item >
auto operator<<( Item item ) &&
-> Sub&&
{
return static_cast<Sub&&>(
move( *this ).Itemlist::operator<<( item )
);
}
...

At least Visual C++ 2017 protested when the cast was just to `Sub&`.

The base class operator<< is also an rvalue-qualified member function,
whose purpose is to support simple hierarchical declarations like

auto some_text()
-> std::string
{
using namespace gui_ext::menu_data;
using std::move;

const auto menu = move( Itemlist{}
<< (Sub{ "App" }
<< Text_item{ 1, "Exit" })
<< (Sub{ "Help" }
<< Text_item{ 2, "About" })
);
return menu.description();
}

Since it seems that my code leads to fruitful discussions and insights
(I learn from it, hopefully others also do), here's the ~full header
that defines Itemlist etc., just data for simple text only menus:


#pragma once

#include <cppx/warnings_suppression.hpp> // CPPX_BEGIN_EXTERNAL,
CPPX_END_EXTERNAL
CPPX_BEGIN_EXTERNAL
// <url: http://www.fltk.org>
#include <FL/Fl.H> // set_fonts
#include <FL/Fl_Draw.H> // Font functions
CPPX_END_EXTERNAL

#include <cppx/text/stdstring-util.hpp> // cppx::To_str
#include <stdlib/extension/type_builders.hpp> // ref_
#include <stdlib/memory.hpp> // std::unique_ptr
#include <stdlib/string.hpp>
#include <stdlib/utility.hpp> // std::(move, forward)
#include <stdlib/vector.hpp>

namespace gui_ext
{
using cppx::To_str; // A simple <<-based string builder.
using std::make_unique;
using std::move;
using std::string;
using std::vector;
using std::unique_ptr;
using namespace stdlib::ext::type_builders; // ref_

namespace menu_data
{
// A top level popup menu or menubar is defined by an Item_list.
// An Item_list is a sequence of Item-s.
// An Item is either a Separator, a Text_item or a Sub (item list).
// A Sub is a Text_item with id 0, plus an Item_list.
// All these things are Thing-s, where a Thing has a
.description().
//
// A menu item hierarchy is expressed by adding things via <<
syntax.

struct Thing
{
inline virtual auto description() const -> string = 0;
inline virtual ~Thing() = 0;
};

inline Thing::~Thing()
{}

inline auto to_string( ref_<const Thing> o )
-> string
{ return o.description(); }

struct Item: Thing {};

struct Separator
: Item
{
auto description() const
-> string override
{ return "-- Separator --"; }
};

struct Text_item
: Item
{
int id;
string text;
string shortcut_description;
string tooltip_text;

auto description() const
-> string override
{ return To_str{} << "Item{" << id << ": “" << text << "”}"; }

Text_item(
const int an_id,
string a_text,
string a_shortcut_description = "",
string a_tooltip_text = ""
)
: id{ an_id }
, text{ move( a_text ) }
, shortcut_description{ move( a_shortcut_description ) }
, tooltip_text{ move( a_tooltip_text ) }
{}
};

struct Itemlist
: Thing
{
vector<unique_ptr<Item>> items;

void append( unique_ptr<Item> p_item )
{
items.emplace_back( move( p_item ) );
}

template< class Item >
auto operator<<( Item item ) &&
-> Itemlist&&
{
append( make_unique<Item>( move( item ) ) );
return move( *this );
}

auto description() const
-> string override
{
To_str s;
s << "Itemlist{";
for( auto const& p_item : items )
{
const bool is_first = (&p_item == &items.front());
if( not is_first ) { s << ", "; }
s << *p_item;
}
s << "}";
return s;
}

Itemlist() {}

Itemlist( Itemlist&& other )
: items{ move( other.items ) }
{}
};

struct Sub
: Text_item
, Itemlist
{
template< class Item >
auto operator<<( Item item ) &&
-> Sub&&
{
return static_cast<Sub&&>(
move( *this ).Itemlist::operator<<( item )
);
}

auto description() const
-> string override
{
return To_str{}
<< "Sub{"
<< Text_item::description() << "→" <<
Itemlist::description()
<< "}";
}

Sub(
string a_text,
string a_shortcut_description = "",
string a_tooltip_text = ""
)
: Text_item{
0, // Id
move( a_text ),
move( a_shortcut_description ),
move( a_tooltip_text )
}
{}

Sub( Sub&& other )
: Text_item{ move( other ) }
, Itemlist( move( other ) )
{}
};
} // namespace menu_data

} // namespace gui_ext


Cheers!,

- Alf

Rosario19

unread,
Jul 8, 2018, 3:37:11 AM7/8/18
to
> << Text_item::description() << "?" <<
>Itemlist::description()
> << "}";
> }
>
> Sub(
> string a_text,
> string a_shortcut_description = "",
> string a_tooltip_text = ""
> )
> : Text_item{
> 0, // Id
> move( a_text ),
> move( a_shortcut_description ),
> move( a_tooltip_text )
> }
> {}
>
> Sub( Sub&& other )
> : Text_item{ move( other ) }
> , Itemlist( move( other ) )
> {}
> };
> } // namespace menu_data
>
>} // namespace gui_ext
>
>
>Cheers!,
>
>- Alf

some Axiom code
--Input un numero a in PI
--output una lista v in in cui:
-- v.1 e' la lunghezza di cifre decimali di a
-- v.(i+2) e' il numero di cifra i(0..9) che ha trovato in a
-- 0 1 2 3 4 5 6 7 8 9
d(a)== -- 1 2 3 4 5 6 7 8 9 10 11 12
n:=0;v:=[0,0,0,0,0,0,0,0,0, 0, 0, 0]
repeat
n:=n+1
r:=a rem 10
v.(r+2):=v.(r+2)+1
a:=a quo 10
a=0=>break
v.1:=n
v

-- Ritorna il precedente numero palidrome rispetto ad 'a' NNI, se r<0
-- ha la particolarita' palpn(-1,0) = 0
-- Ritorna il successivo numero palidrome rispetto ad 'a' NNI, se r>0
-- Se r=0 ritorna 1 se 'a' e' palindrome, 0 se 'a' non e' palindrome
palpn(r,a)==
q:=d(a);n:=q.1 -- n la lunghezza in cifre di base 10 di a
r<0 and a=0 =>a
r<0 and(n=1 or (q.3=1 and q.3+q.2=n)) =>a-1
r<0 and q.3=2 and q.3+q.2=n and a rem 10=1=>a-2
r>0 and n=1 and a<9=>a+1
r>0 and q.11=n =>a+2
r=0 and n=1 =>1
m:=n quo 2
v:=a quo (10^m)
repeat
-- because here not there is a goto instruction i have to use repeat
vv:=v; w:=v
if n rem 2>0 then w:=w quo 10
repeat
vv:=10*vv+w rem 10
w:=w quo 10
w=0=>break
r<0=>(vv<a=>return vv; v:=v-1)
r>0=>(vv>a=>return vv; v:=v+1)
r=0=>(vv=a=>return 1;return 0)
vv

Alf P. Steinbach

unread,
Jul 8, 2018, 8:35:55 AM7/8/18
to
On 08.07.2018 04:27, Alf P. Steinbach wrote:
> I was baffled why I couldn't static_cast to ordinary reference in this
> code, and then apply move(), rather than static_cast to rvalue
> reference, doing the work of move() myself:
>
>     struct Sub
>         : Text_item
>         , Itemlist
>     {
>         template< class Item >
>         auto operator<<( Item item ) &&
>             -> Sub&&
>         {
>             return static_cast<Sub&&>(
>                 move( *this ).Itemlist::operator<<( item )
>                 );
>         }
>     ...
>
> At least Visual C++ 2017 protested when the cast was just to `Sub&`.

Now at daytime, rather than very late night, I understand that one can't
cast a temporary (which is how the rvalue reference function result
appears) directly to an ordinary reference.

The night-time thinking was an invalid hazy generalization of the
situation where an rvalue reference decays to ordinary reference, e.g.
for function arguments.

It would probably be difficult to explain these different behaviors of
rvalue references, depending on context, to a beginner...


Cheers!,

- Alf

Juha Nieminen

unread,
Jul 9, 2018, 3:58:07 AM7/9/18
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> struct Sub
> : Text_item
> , Itemlist
> {
> template< class Item >
> auto operator<<( Item item ) &&
> -> Sub&&
> {
> return static_cast<Sub&&>(
> move( *this ).Itemlist::operator<<( item )
> );
> }

You have an uncanny ability of writing C++ in a form that causes even a
very experienced C++ programmer to have to spend an unreasonable amount
of time staring at the code trying to figure out what it means.

Alf P. Steinbach

unread,
Jul 9, 2018, 4:23:34 AM7/9/18
to
That's interesting, when ignoring the personal jab. On what line does it
get problematic for you?

As reported, for me, very late at night, it was the `static_cast`,
somehow then conflating the rules for rvalue-ref-as-return with the
rules of rvalue-ref-as-argument.


Cheers!,

- Alf

bitrex

unread,
Jul 9, 2018, 9:34:52 AM7/9/18
to
If one is actually utilizing the new features the modern C++ standards
have available code is often not going to look a lot like what "very
experienced" C++ programmers remember it looking like in 1997 that's
just the way it is.

woodb...@gmail.com

unread,
Jul 9, 2018, 9:38:21 AM7/9/18
to
That's his schtick. It's a thick accent he's been
honing for years.


Brian
Ebenezer Enterprises
https://github.com/Ebenezer-group/onwards

Bart

unread,
Jul 9, 2018, 10:37:49 AM7/9/18
to
It sounds like C++ programmers expect new features to be more
complicated and harder to understand than what is already in the language.

In contrast, I consider a useful new feature ought to make things
simpler and easier.

I actually haven't got a clue what the code at the top is doing. However
in the clc group, C++ is frequently sold as a language which is so much
easier and better than C because it has so many built-in solutions to
things that have to be re-implemented in C.

It's odd then that I rarely come across a C++ example which I can follow
compared to the C equivalent. Or maybe the C++ experts here just like to
show off their skills at writing incomprehensible code, which is not
typical of normal programs.

--
bart

bitrex

unread,
Jul 9, 2018, 11:28:00 AM7/9/18
to
Sounds like they're "selling" C++ wrong, whomever is selling it that
way. The _runtime_ component of C++, the actual stuff that gets parsed
directly into object code, is really nothing much more than a mild
superset of C, a simplistic 1970s-style statically-typed language.
That's component #1 of C++. Component #2 is a powerful modern
compile-time meta-programming language that's used to manipulate the
component #1s into zero-overhead abstractions.

> It's odd then that I rarely come across a C++ example which I can follow
> compared to the C equivalent. Or maybe the C++ experts here just like to
> show off their skills at writing incomprehensible code, which is not
> typical of normal programs.

They're exploiting Component #2 for what it's good for. If you're not
doing that you're...basically just programming in a kind of dumpy obtuse
variant of C I won't deny it, there's really not much advantage to using
C++ at that point over many other modern compiled languages like Go,
Rust, and so forth. Standing by itself Component #1 ain't shit, or at
least no more or less the shit than C.



Alf P. Steinbach

unread,
Jul 9, 2018, 11:56:21 AM7/9/18
to
I agree with that.


> I actually haven't got a clue what the code at the top is doing.

Yes, it's pretty intricate code, using C++14 language features, which
look odd and have strange rules.

Here's a breakdown:

struct Sub
: Text_item
, Itemlist

^ Declares a class called Sub, that inherits from -- Is A -- class
Text_item and from class Itemlist.

What Text_item and Itemlist are doesn't matter.

template< class Item >

^ Introduces a template of something, that can be used with a type that
can be wildly different types in different usage contexts. The concrete
type used in any given context is called Item in this definition.

auto operator<<( Item item ) &&
-> Sub&&

^ The "auto operator<<(" starts a declaration of a member function
called "operator<<". "auto" says that the return type is specified after
the function head, either implicitly via a "return" statement (a C++14
deduced return type) or explicitly via a "->" return type specification
(C++11 trailing return type syntax). The function name "operator<<"
means that this function can be called via operator notation, e.g. the
invocation "o << an_item", which is how e.g. iostreams work.

"( Item item )" is the function's formal argument list, just like in C.
Here an Item is passed by value.

"&&" means that this function can only be called via an rvalue
expression, essentially calling it on a temporary. More precisely it can
also be called on the result of a function that returns an rvalue
reference, because that acts as if it were a temporary. So, the "&&" is
an rvalue qualification of the member function. There are also lvalue
qualification "&", and const lvalue qualification "const &".

-> Sub&&

Specifies that the return type is rvalue-reference-to-Sub, i.e. (as-if)
a reference to a temporary Sub object.

return static_cast<Sub&&>(
move( *this ).Itemlist::operator<<( item )
);

^ This rather ungrokable mess just invokes the base class "operator<<",
and, via the "static_cast", downcasts the result to this class. It
should IMHO have been trivial to do that, it's just a /forwarding/ of
the call to a base class method, but it isn't trivial.

Instead of downcasting the base class' result it could have been
separated into two statements like this:

move( *this ).Itemlist::operator<<( item );
return move( *this );

That's perhaps better for discussion. The "move( *this )" doesn't
actually move anything. It uses "std::move" as a /cast/ to create an
rvalue reference to the current object, needed in the first line because
the base class "operator<<" can only be called via an rvalue expression.
The ".Itemlist::operator<<" then refers to the "operator" defined in the
base class "Itemlist". And the "( item )" expresses the call with "item"
as argument, just like in C.

"move( *this )" is also needed in the return statement, since this
"operator<<", like the one in the base class, returns an rvalue reference.

In the originally posted code there is no "move( *this )" for the result
because that's expressed by a "static_cast".


> However
> in the clc group, C++ is frequently sold as a language which is so much
> easier and better than C because it has so many built-in solutions to
> things that have to be re-implemented in C.

The rvalue stuff in this code addresses problems that stem from what I'd
call a cognitive dissonance in the C++ type system.

The original C lvalue versus rvalue expression classification was
presumably useful to help the compiler put temporary results in
registers, where on most machines one couldn't take the address. Also
one couldn't assign to rvalues. The put-in-registers made for execution
efficiency, and the can't-assign-to made for programmer efficiency; it
all made sense.

In C++ there are rvalue expressions that denote objects of arbitrary
size and complexity, that necessarily do live in main memory, and that
generally /can/ be assigned to. That doesn't make so much sense. So the
code to handle this, with the old distinction still ruling, gets ungood.


> It's odd then that I rarely come across a C++ example which I can follow
> compared to the C equivalent. Or maybe the C++ experts here just like to
> show off their skills at writing incomprehensible code, which is not
> typical of normal programs.
There must be many books and articles about C++ that cater to C
programmers.

If nothing else, I enjoyed learning C++ from the original "The C++
Programming Language" by Bjarne Stroustrup. I think that was published
in 1985. That first edition was of the same general form as the earlier
"The C Programming Language" by Kernighan & Ritchie.

The first edition of TCPPL was about the pre-standard simpler language
that's still to be found within all the complexity of modern C++. I
think that book was before exceptions and templates. Exceptions were
introduced around 1989, IIRC, templates later.


Cheers!,

- Alf

Vir Campestris

unread,
Jul 9, 2018, 4:52:40 PM7/9/18
to
On 09/07/2018 15:37, Bart wrote:
> It's odd then that I rarely come across a C++ example which I can follow
> compared to the C equivalent. Or maybe the C++ experts here just like to
> show off their skills at writing incomprehensible code, which is not
> typical of normal programs.

The last heavyweight bit of C I wrote was a hash set. I had to use C as
it was running bare metal, so I couldn't use anything nice like new.

I can assure you that the several pages of code were a lot harder to
read than the C++ equivalent, most of which would have just pulled in STL.

Andy

Ian Collins

unread,
Jul 9, 2018, 11:25:25 PM7/9/18
to
Which is what most of C++14 did...

> I actually haven't got a clue what the code at the top is doing. However
> in the clc group, C++ is frequently sold as a language which is so much
> easier and better than C because it has so many built-in solutions to
> things that have to be re-implemented in C.

The code is hard to follow, partly due to the unusual (to my eyes)
layout compounded by the gratuitous use of suffix return.. I'm sure if
I submitted it to a code review I'd get more than a few WTF? responses!

Most builtin or library features such as containers and algorithms do
make things easier and better than C.

> It's odd then that I rarely come across a C++ example which I can follow
> compared to the C equivalent. Or maybe the C++ experts here just like to
> show off their skills at writing incomprehensible code, which is not
> typical of normal programs.

Most C++ code I see is pretty mundane. The "clever" stuff is usually
confined to libraries.

--
Ian.


Juha Nieminen

unread,
Jul 10, 2018, 2:29:51 AM7/10/18
to
bitrex <us...@example.net> wrote:
> If one is actually utilizing the new features the modern C++ standards
> have available code is often not going to look a lot like what "very
> experienced" C++ programmers remember it looking like in 1997 that's
> just the way it is.

What makes you think that my comment had anything to do with C++98 vs C++11?

Code can be made more obfuscated in several ways, such as using unusual
and confusing indentation and line breaks, among a myriad other techniques.
Also, using alternative syntax just for the sake of it, even though it's
the less commonly used one, can make code needlessly hard to read.

As an example, one of the major reasons why the trailing return type
syntax for function declarations was introduced is that it makes it
simpler to declare the return type when it depends on the names of the
function paramers. The classical example is:

template <class T, class U>
auto add(T t, U u) -> decltype(t + u);

Achieving this was possible in C++98, but it was much more complicated.
This syntax introduced in C++11 makes it much simpler.

However, once you start writing things like:

auto main()
-> int

it just seems needlessly complicated for no good reason. Everybody and
their grandmother understands "int main()", and using the trailing type
syntax serves mostly the use of making the code harder to read.

(It also kind of reminds me, in a way, of how in K&R C the types of the
function parameter were not specified inside the parentheses in front of
the parameter names, but separately after the parentheses. So, in a weird
sense, it feels a bit like going back in time to the 80's. And not
necessarily in a good way.)

I also find it odd how he's fond of the more verbose trailing type syntax,
while at the same time eschewing specifying whether he's inheriting the
struct publicly or privately from the base classes.

Verbosity isn't itself a bad thing, especially when it makes the code
easier to read and understand. But using additional verbosity in situations
that makes the code harder to understand, and at the same time avoiding
verbosity in situations when doing so also makes the code harder to
understand, is a bit baffling. It almost feels deliberate.

If you are inheriting your class or struct from something, always specify
the type of inneritance. Saying "struct A: B, C" is just confusing. Is
it public inheritance, or is it private inheritance? Just put the keywords
there to clarify.

bol...@cylonhq.com

unread,
Jul 10, 2018, 5:48:48 AM7/10/18
to
You ever read the STL source code? Its enough to make anyone weep. There's
no reason a similar library (albeit without the templating) couldn't be
written in C and then the application code using it would look a lot tidier.

bol...@cylonhq.com

unread,
Jul 10, 2018, 5:55:17 AM7/10/18
to
On Mon, 9 Jul 2018 17:56:11 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>On 09.07.2018 16:37, Bart wrote:
>Specifies that the return type is rvalue-reference-to-Sub, i.e. (as-if)
>a reference to a temporary Sub object.
>
> return static_cast<Sub&&>(
> move( *this ).Itemlist::operator<<( item )
> );

And some greybeards wonder why the kids are avoiding C++. God almighty, its
virtually unparsable , and thats just 1 line. If I saw a whole program full
of this crap I'd just dump the whole thing and re-write it.

How exactly does any of this syntatic masturbation solve any problems? Because
lets remember, a programming language is just a tool, not an end in itself.

>^ This rather ungrokable mess just invokes the base class "operator<<",

Well you wrote it.

Juha Nieminen

unread,
Jul 10, 2018, 7:12:27 AM7/10/18
to
bol...@cylonhq.com wrote:
> How exactly does any of this syntatic masturbation solve any problems? Because
> lets remember, a programming language is just a tool, not an end in itself.

Indeed. Syntactic tools should be used when they make sense, and make the code
clearer, easier to use, safer, more understandable, or all of the above.
Using them just for the sake of it, especially if it makes the code harder
to understand, and especially if there are clearer alternatives, makes no
sense.

Juha Nieminen

unread,
Jul 10, 2018, 7:20:46 AM7/10/18
to
bol...@cylonhq.com wrote:
> You ever read the STL source code? Its enough to make anyone weep. There's
> no reason a similar library (albeit without the templating) couldn't be
> written in C and then the application code using it would look a lot tidier.

The reason why templated code in the standard library tends to be complex is
for two main reasons:

Firstly, it needs to make all kinds of compile-time sanity checks that are a
bit complicated to perform (but which the regular programmer doesn't need to
worry about). These have to be done to ensure that the class or function does
what it should, and is as hard to use incorrectly as possible.

For example, suppose you have something like this:

std::vector<std::size_t> v;
v(10, 20);

A naive implementation of std::vector would fail to compile that. Why?
Because it will try to call the version of the constructor taking two
iterators (and then fail to compile because those are not iterators).

However, the standard std::vector will compile, and do the right thing
(ie. create a vector of 10 elements, each having the value 20.) How?
Well, that's the complicated part, which makes the source code a bit
complex.

And if you *do* give it two iterators of the same type, it will still
compile and do the right thing.

Secondly, the standard library headers tend to look very messy because
all internal names tend to be prefixed with two underscores. This is
done out of necessity, so that user-defined precompiler macros won't
mess things up and cause weird compiler errors (or in the worst case
scenario compilable code that's broken). (Remember that the standard
forbids the user from using names with two leading underscores.
If you use them, all bets are off. As long as you don't use them,
you ought to be safe.)

Bart

unread,
Jul 10, 2018, 8:24:36 AM7/10/18
to
On 10/07/2018 12:20, Juha Nieminen wrote:
> bol...@cylonhq.com wrote:
>> You ever read the STL source code? Its enough to make anyone weep. There's
>> no reason a similar library (albeit without the templating) couldn't be
>> written in C and then the application code using it would look a lot tidier.
>
> The reason why templated code in the standard library tends to be complex is
> for two main reasons:
>
> Firstly, it needs to make all kinds of compile-time sanity checks that are a
> bit complicated to perform (but which the regular programmer doesn't need to
> worry about). These have to be done to ensure that the class or function does
> what it should, and is as hard to use incorrectly as possible.
>
> For example, suppose you have something like this:
>
> std::vector<std::size_t> v;
> v(10, 20);
>
> A naive implementation of std::vector would fail to compile that. Why?
> Because it will try to call the version of the constructor taking two
> iterators (and then fail to compile because those are not iterators).

I couldn't get this to compile at all. (Note I don't normally write C++
code and I used an online 'rextester.com' C++ compiler. I'm writing this
as an observer.)

First, it needed '#include <vector>' (Why? isn't it part of std?). Then
it couldn't find a match for 'unsigned long long int' (size_t). Using
just <int> was OK, but then it didn't understand v(10) or v(10,20). I
finally got this compiled:

std::vector<int> v = {10,20,30,40};

but if I then added:

std::cout << v << std::endl;

I got several hundred lines of error messages.

So although your point is about why internal libraries might be
complicated, mine is that even what should be straightforward user code
is not that friendly!

I'd write this stuff in dynamic code like this:

v := (10,20,30,40)
println v # output: (10,20,30,40)

v is a writeable, flexible-length list with variant elements. A
flexible, packed array of a fixed element type closest to the C++ is
doable although it is a little outside the language:

v := new(array,word64,10,20) # word32 == size_t
println v, v.bounds

This now matches your example and the output now is
(20,20,20,20,20,20,20,20,20,20) 1..10

What I'm saying is that the hugely complex language building features of
C++ seem to promise this sort of simplicity in user code (even in a
static language rather than my dynamic examples), but I'm not seeing it.
The user code syntax seems rather fragile.

--
bart

Alf P. Steinbach

unread,
Jul 10, 2018, 8:37:17 AM7/10/18
to
There are some levels of understanding involved.

I've always disagreed strongly with those who maintain that one who
doesn't have 20 years experience in designing cars, can't evaluate a car
design with square wheels. Because that problem is obvious. The argument
that one is disqualified is a purely associative one, idiotic IMHO,
although it must be said that that argument often /works/, when it
appeals to authority in a direction that the herd has experience with.

But that's not what you're doing here. You're not evaluating on the
basis of seeing square wheels or something like that. You're evaluating
on the basis of feeling uneasy with new language features, and, it seems
to me, on the basis of needing much time to understand unfamiliar
combinations of simple features, that involve 3 or more relationships.

That's like the close-voters on Stack Overflow who decide that someone's
question must be off-topic or nonsense because they don't understand it,
sometimes even in the face of very clear answers to that question.

That is, they're using their inflated opinions of their own competence,
to infer from their own lack of understanding that the question must be
nonsense. Or else they would have understood it, surely. Their reaction
is not to ask about anything, for what could there be to ask about?, and
besides that would be outside their comfort zone; they instead simply
vote to close, to get this to them affronting nonsense out of the way.


Cheers!,

- Alf (social focus mode)

Juha Nieminen

unread,
Jul 10, 2018, 8:58:58 AM7/10/18
to
Bart <b...@freeuk.com> wrote:
>> std::vector<std::size_t> v;
>> v(10, 20);

> I couldn't get this to compile at all.

I made a mistake in that code. What I meant to say was:

std::vector<std::size_t> v(10, 20);

> std::vector<int> v = {10,20,30,40};

It's not doing the same thing at all. Nor is it demonstrating the point
of my post.

> but if I then added:
>
> std::cout << v << std::endl;
>
> I got several hundred lines of error messages.

Only the first one is relevant and will tell you the problem.

What exactly do you think should happen if you try to output a
vector to a stream?

> I'd write this stuff in dynamic code like this:
>
> v := (10,20,30,40)
> println v # output: (10,20,30,40)

Why should it write "(10,20,30,40)"?

Why not "10, 20, 30, 40"? Or "[10, 20, 30, 40]"? Or "[10,20,30,40]"?
Or each number in its own line? Or the about one million other possible
variations? Why is that the "correct" one?

> What I'm saying is that the hugely complex language building features of
> C++ seem to promise this sort of simplicity in user code (even in a
> static language rather than my dynamic examples), but I'm not seeing it.
> The user code syntax seems rather fragile.

Fragile... What exactly is it that you want? For the compiler to guess
using AI what you *really* wanted to say, even though it's not syntactically
correct?

bol...@cylonhq.com

unread,
Jul 10, 2018, 9:01:10 AM7/10/18
to
On Tue, 10 Jul 2018 14:37:07 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>There are some levels of understanding involved.

Naturally you're conversant with all these levels arn't you.

>I've always disagreed strongly with those who maintain that one who
>doesn't have 20 years experience in designing cars, can't evaluate a car
>design with square wheels. Because that problem is obvious. The argument
>that one is disqualified is a purely associative one, idiotic IMHO,
>although it must be said that that argument often /works/, when it
>appeals to authority in a direction that the herd has experience with.
>
>But that's not what you're doing here. You're not evaluating on the
>basis of seeing square wheels or something like that. You're evaluating
>on the basis of feeling uneasy with new language features, and, it seems
>to me, on the basis of needing much time to understand unfamiliar
>combinations of simple features, that involve 3 or more relationships.

If you want to use a car analogy - you're the sort of designer who doesn't
actually drive but thought it would be a great idea to have everything
controlled by a touchscreen. After all, touchscreen interfaces are common
now , everyone uses them and it requires less components. Unfortunately you
completely forgot that when driving one can't look at a touchscreen and with
zero haptic feedback they're next to useless in that situation so even changing
a radio channel or setting the air con becomes impossible unless topped.
Technology for its own sake.

Similarly with your code - you write code to impress and use as much cutting
edge syntax as you can because its there, not because its appropriate or would
be maintainable in the wild. Syntax for its own sake.

Alf P. Steinbach

unread,
Jul 10, 2018, 9:37:53 AM7/10/18
to
On 10.07.2018 14:58, Juha Nieminen wrote:
> Bart <b...@freeuk.com> wrote:
>>> std::vector<std::size_t> v;
>>> v(10, 20);
>
>> I couldn't get this to compile at all.
>
> I made a mistake in that code. What I meant to say was:
>
> std::vector<std::size_t> v(10, 20);
>
>> std::vector<int> v = {10,20,30,40};
>
> It's not doing the same thing at all. Nor is it demonstrating the point
> of my post.
>
>> but if I then added:
>>
>> std::cout << v << std::endl;
>>
>> I got several hundred lines of error messages.
>
> Only the first one is relevant and will tell you the problem.
>
> What exactly do you think should happen if you try to output a
> vector to a stream?

Something reasonable.

It doesn't matter exactly what the output is, except for the distinction
between display for humans, versus round-trip conversion support where
the text representation can be parsed and yield the original data.

I've briefly encountered a number of libraries that produce reasonable
text output of any standard library container. So it's possible. It's
just not standardized and readily available, which would have been nice.


> [snip]
> Fragile... What exactly is it that you want? For the compiler to guess
> using AI what you *really* wanted to say, even though it's not syntactically
> correct?

IMO most of the problems with silly error avalanches in C++ stem from
using too low level language features to directly implement higher level
stuff, because the language lacks the middle level of abstraction.

For example, because of the lack of abstraction an error message will
typically show the complete template instantiation for something,
instead of just a simple recognizable name like `std::string`.

With C++ templates we're essentially using `goto` directly instead of
structured flow control like `for` loops. So, in that analogy, the
errors don't relate to loop variant and invariants, or something like
that, but instead to invalid position for label, computed goto with
possibly invalid resulting jump address, ... blah blah details details,
of no interest to one whose goal is to loop over items of a collection.


Cheers!,

- Alf

Bart

unread,
Jul 10, 2018, 10:02:19 AM7/10/18
to
On 10/07/2018 13:58, Juha Nieminen wrote:
> Bart <b...@freeuk.com> wrote:
>>> std::vector<std::size_t> v;
>>> v(10, 20);
>
>> I couldn't get this to compile at all.
>
> I made a mistake in that code. What I meant to say was:
>
> std::vector<std::size_t> v(10, 20);
>
>> std::vector<int> v = {10,20,30,40};
>
> It's not doing the same thing at all. Nor is it demonstrating the point
> of my post.

The end result was presumably to create an instance of a vector of
size_t initialised to N elements set to some values (I suppose I could
have initialised mine to ten 20s).

> What exactly do you think should happen if you try to output a
> vector to a stream?
>
>> I'd write this stuff in dynamic code like this:
>>
>> v := (10,20,30,40)
>> println v # output: (10,20,30,40)
>
> Why should it write "(10,20,30,40)"?

Because that's the default output for that type in this language? The
same as you might get in Python or Ruby in Javascript; the details will
vary but you will get the values 10, 20, 30, and 40 printed out in some
form and in that order.

> Why not "10, 20, 30, 40"? Or "[10, 20, 30, 40]"? Or "[10,20,30,40]"?
> Or each number in its own line? Or the about one million other possible
> variations? Why is that the "correct" one?

You can write a printlist() routine for a generic list to get it
displayed as you want.

Or superimpose a user type on it that requires a certain output style
that will use a dedicated stringify routine. But for quickly displaying
the value(s) of a variable, it doesn't matter.

(How would a debugger for C++ display such a vector?)

>> What I'm saying is that the hugely complex language building features of
>> C++ seem to promise this sort of simplicity in user code (even in a
>> static language rather than my dynamic examples), but I'm not seeing it.
>> The user code syntax seems rather fragile.
>
> Fragile... What exactly is it that you want? For the compiler to guess
> using AI what you *really* wanted to say, even though it's not syntactically
> correct?

I'm saying it is fragile.

What are we declaring here? Some sort of flexible, ie. expandable array
of a specific type? You can express that in C with a tweak in the syntax:

int v[flex] = {10,20,30,40};

Of course, 'flex' arrays would need to be implemented. The point is that
such syntax for them is more robust and also tidier (and more consistent
with existing arrays) than the C++ where such things have to be
implemented using its language building features. And the syntax for
invoking those has limitations.


--
bart


red floyd

unread,
Jul 10, 2018, 11:22:59 AM7/10/18
to
On 07/07/2018 07:27 PM, Alf P. Steinbach wrote:
> I was baffled why I couldn't static_cast to ordinary reference in this
> code, and then apply move(), rather than static_cast to rvalue
> reference, doing the work of move() myself:
>
>     struct Sub
>         : Text_item
>         , Itemlist
>     {
>         template< class Item >
>         auto operator<<( Item item ) &&
>             -> Sub&&
>         {
>             return static_cast<Sub&&>(
>                 move( *this ).Itemlist::operator<<( item )
>                 );
>         }
>     ...
>

OK, I'll ask the obvious.

Why (*this).Itemlist instead of this->Itemlist

I'm assuming the explicit refernce to this is due to some template
weirdness. Otherwise the question becomes, why explicitly specify
"this"?

Alf P. Steinbach

unread,
Jul 10, 2018, 11:44:49 AM7/10/18
to
This is a should-have-been-simple-really forwarding to the base class
`operator<<`, which is rvalue-qualified.

The rvalue qualification means that it must be called on an rvalue
expression. I would be happy to learn of some better way than the
`move(*this)`. It was the first I could think of, but it is very very
ugly to my eyes... So, suggestions/ideas/knowledge very welcome.

It's rvalue-qualified so the machinery can be used to construct a menu
in a single expression, like this (it's my actual code at the moment):


$with( gui_ext::Auto_parent{ *this } )
{
using namespace gui_ext::menu_data;
const auto& menubar = *new gui_ext::Menu_bar{
Itemlist{}
<< (Sub{ "App" }
<< Text_item{ 0, "Blah" }
<< Text_item{ 0, "Blah blah" }
<< Separator{}
<< Text_item{ Cmd::app_exit, "Exit" })
<< (Sub{ "Help" }
<< Text_item{ 0, "Help" }
<< Separator{}
<< Text_item{ Cmd::help_about, "About" }),
[this]( const int id ) { on_menuitem_picked( id ); }
};

...


In between the resulting FLTK menu bar and the pure data Itemlist's <<
machinery, is a generator class Menu_bar that translates the hierarchy
of menu items to FLTK menu text paths, for FLTK menu creation. Yes, it's
incredible, but one uses the actual country-specific menu text, forming
a path with "/" as separator, to specify an item's hierarchical
position. It's so insane that I could not believe it, I wasted a day
searching for the more normal functionality that I felt had to be there.

Another thing about FLTK, it has an implicit-parent window scheme where
any new widget is automatically put, hence no explicit parent specs above.

The translation code, mapping the hierarchy of menu data items to FLTK
widget, is in the constructor of Menu_bar. It's currently some 70+
lines, far more than I consider reasonable for a function body. But I
see no good simple ways to refactor it. I can post it here if someone's
willing to take a look and say, you idiot Alf, here's how to do it. E.g.
recursive instead of my iterative code, or something?


Cheers!,

- Alf

Rosario19

unread,
Jul 10, 2018, 11:55:58 AM7/10/18
to
On Mon, 9 Jul 2018 10:23:25 +0200, "Alf P. Steinbach" wrote:

>On 09.07.2018 09:57, Juha Nieminen wrote:
>> Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
>>> struct Sub
>>> : Text_item
>>> , Itemlist

here ther is for me the 1 problem
class sub:Tex_item could mean that sub is a 'subset' of class Tex_item
(this possible is ok)
what does it mean "sub:Tex_item,Itemlist" (the ",Itemlist")?

>>> {
>>> template< class Item >
>>> auto operator<<( Item item ) &&

i never used auto, but here the problem is for me conceptual: what
does it mean "&&"? it appear it means "reference reference"
i never tought on that nor used
than i miss 100% the meaning of:

"auto operator<<( Item item ) && -> Sub&&"

>>> -> Sub&&
>>> {
>>> return static_cast<Sub&&>(

i used only C cast ()

>>> move( *this ).Itemlist::operator<<( item )

this would mean that move has as argument *this, its result is one
type has one .Itemlist::operator<<()
apply to item...

>>> );
>>> }
>>

Manfred

unread,
Jul 10, 2018, 11:56:50 AM7/10/18
to
On 7/10/2018 4:02 PM, Bart wrote:
> On 10/07/2018 13:58, Juha Nieminen wrote:
>> Bart <b...@freeuk.com> wrote:
>>>>     std::vector<std::size_t> v;
>>>>     v(10, 20);
>>
>>> I couldn't get this to compile at all.
>>
>> I made a mistake in that code. What I meant to say was:
>>
>>    std::vector<std::size_t> v(10, 20);
>>
>>>      std::vector<int> v = {10,20,30,40};
>>
>> It's not doing the same thing at all. Nor is it demonstrating the point
>> of my post.
>
> The end result was presumably to create an instance of a vector of
> size_t initialised to N elements set to some values (I suppose I could
> have initialised mine to ten 20s).

C++ gives you that, it is called initializer list, and this is what you
came across - the defining syntax is a brace-enclosed list of elements,
separated by commas.
This is different from the 2 argument /constructor/ (no list) which
takes 1 value and a number of elements.
These are two logically different constructs, which justify the
different syntax.

>
>> What exactly do you think should happen if you try to output a
>> vector to a stream?
>>
>>> I'd write this stuff in dynamic code like this:
>>>
>>>      v := (10,20,30,40)
>>>      println v               # output: (10,20,30,40)
>>
>> Why should it write "(10,20,30,40)"?
>
> Because that's the default output for that type in this language? The
> same as you might get in Python or Ruby in Javascript; the details will
> vary but you will get the values 10, 20, 30, and 40 printed out in some
> form and in that order.

Well, C++ does not have a default output for all types - in fact there
are 2 kind of outputs: the one inherited from C (stdio) and the standard
C++ library, which basically offers output operators for fundamental
types (ints, floats, strings) and little (or nothing?) more, it's that
simple!

Yes, this requires that you write output operators for more complex
types (or use a library), but a) in any serious project you /want/ to do
just that, so that /you/ control the output format, and b) you don't
have to learn what is the default output for those types (C++ is big
enough without adding this too, I believe)
In fact the examples of Python, Ruby, Javascript are IMHO only good for
contexts where the actual output format is not relevant, and this is
IMHO only acceptable for e.g. in-house tools. Moreover, these languages
require that you learn what is the default format, and how to override
it, which I find annoying whenever I need to control my own output.

>
>> Why not "10, 20, 30, 40"? Or "[10, 20, 30, 40]"? Or "[10,20,30,40]"?
>> Or each number in its own line? Or the about one million other possible
>> variations? Why is that the "correct" one?
>
> You can write a printlist() routine for a generic list to get it
> displayed as you want.
>
> Or superimpose a user type on it that requires a certain output style
> that will use a dedicated stringify routine. But for quickly displaying
> the value(s) of a variable, it doesn't matter.

In C++ you would do neither, you would define a custom insertion
operator (operator <<) that does the job without the need to modify the
type system.

>
> (How would a debugger for C++ display such a vector?)
(both VS and gdb display it their own way)
>
>>> What I'm saying is that the hugely complex language building features of
>>> C++ seem to promise this sort of simplicity in user code (even in a
>>> static language rather than my dynamic examples), but I'm not seeing it.
>>> The user code syntax seems rather fragile.
I believe it can be agreed that simplicity is not a promise of C++, in
fact it seems that nowadays Bjarne is concerned that the language is
becoming (has already?) too complex.

>>
>> Fragile... What exactly is it that you want? For the compiler to guess
>> using AI what you *really* wanted to say, even though it's not
>> syntactically
>> correct?
>
> I'm saying it is fragile.
>
> What are we declaring here? Some sort of flexible, ie. expandable array
> of a specific type?

Recalling:
std::vector<std::size_t> v(10, 20);

This declares an object v of type "vector of size_t's" which is a
template instantiation of a class template defined in the standard
library (which is the same as a user-defined template as far as the
language is concerned).
I see nothing fragile in it, and it is clearly different from a raw
array (which would be:
size_t v[length];
)

You may say it is complex or verbose, but I wouldn't define it fragile.


You can express that in C with a tweak in the syntax:
>
>    int v[flex] = {10,20,30,40};
>
> Of course, 'flex' arrays would need to be implemented. The point is that
> such syntax for them is more robust and also tidier (and more consistent
> with existing arrays) than the C++ where such things have to be
> implemented using its language building features. And the syntax for
> invoking those has limitations.

The way I see it, having flex arrays look like ordinary arrays, but
behave differently, would be more fragile than std::vector, and if they
were implemented in the language itself instead of a library, they would
make the whole language more fragile (i.e. rigid and hard to maintain)

Manfred

unread,
Jul 10, 2018, 2:02:11 PM7/10/18
to
On 7/10/2018 7:23 PM, Stefan Ram wrote:
> Manfred <non...@add.invalid> writes:
>> C++ gives you that, it is called initializer list, and this is what you
>> came across - the defining syntax is a brace-enclosed list of elements,
>> separated by commas.
>> This is different from the 2 argument /constructor/ (no list) which
>> takes 1 value and a number of elements.
>> These are two logically different constructs, which justify the
>> different syntax.
>
> main.cpp
>
> #include <iostream>
> #include <ostream>
> #include <string>
> using namespace ::std::literals;
>
> struct two_argument_constructor_no_list
> { two_argument_constructor_no_list
> ( int const one_value, int const a_number_of_elements )
> { ::std::cout << "two_argument_constructor_no_list\n"s; }};
>
> #define INITIALIZER_LIST { 1, 2 }
>
> int main(){ two_argument_constructor_no_list INITIALIZER_LIST; }
>
> transcript
>
> two_argument_constructor_no_list
>

;)

http://shop.oreilly.com/product/0636920033707.do
Item 7

Vir Campestris

unread,
Jul 10, 2018, 6:11:11 PM7/10/18
to
On 10/07/2018 10:48, bol...@cylonHQ.com wrote:
> You ever read the STL source code? Its enough to make anyone weep. There's
> no reason a similar library (albeit without the templating) couldn't be
> written in C and then the application code using it would look a lot tidier.

The whole point of the standard TEMPLATE library is the templates.

But yes, I have read it. And yes, it's horrible.

Andy

Vir Campestris

unread,
Jul 10, 2018, 6:20:51 PM7/10/18
to
On 10/07/2018 07:29, Juha Nieminen wrote:
> As an example, one of the major reasons why the trailing return type
> syntax for function declarations was introduced is that it makes it
> simpler to declare the return type when it depends on the names of the
> function paramers. The classical example is:
>
> template <class T, class U>
> auto add(T t, U u) -> decltype(t + u);
>
> Achieving this was possible in C++98, but it was much more complicated.
> This syntax introduced in C++11 makes it much simpler.
>
> However, once you start writing things like:
>
> auto main()
> -> int
>
> it just seems needlessly complicated for no good reason. Everybody and
> their grandmother understands "int main()", and using the trailing type
> syntax serves mostly the use of making the code harder to read.

I'll bite.

Back when C was invented the return type should have been last. After
all, it's the last thing you'll need from the function. But it wasn't.

Now there are reasons for having it last, and that's why the new syntax.

Trouble is we're all old fashioned C programmers at heart, and don't
like change... so the new one looks odd.

If you ever start on a green field project with a code standard that
forces it you'll be used to it in 3 months, and the old one will look odd.

(but I don't think I've started on a greenfield project since 19-something)

Andy

Bart

unread,
Jul 10, 2018, 6:47:34 PM7/10/18
to
On 10/07/2018 23:20, Vir Campestris wrote:
> On 10/07/2018 07:29, Juha Nieminen wrote:
>> As an example, one of the major reasons why the trailing return type
>> syntax for function declarations was introduced is that it makes it
>> simpler to declare the return type when it depends on the names of the
>> function paramers. The classical example is:
>>
>>    template <class T, class U>
>>    auto add(T t, U u) -> decltype(t + u);
>>
>> Achieving this was possible in C++98, but it was much more complicated.
>> This syntax introduced in C++11 makes it much simpler.
>>
>> However, once you start writing things like:
>>
>>    auto main()
>>      -> int
>>
>> it just seems needlessly complicated for no good reason. Everybody and
>> their grandmother understands "int main()", and using the trailing type
>> syntax serves mostly the use of making the code harder to read.
>
> I'll bite.
>
> Back when C was invented the return type should have been last. After
> all, it's the last thing you'll need from the function. But it wasn't.
>
> Now there are reasons for having it last, and that's why the new syntax.
>
> Trouble is we're all old fashioned C programmers at heart, and don't
> like change... so the new one looks odd.
>

But then the 'auto' keyword looks odd; what does it mean, since here
it's not working out the return type for itself? Perhaps try this:

#define function auto

function main() -> int ...

and join the half of the world's languages which use a keyword to
introduce a function definition.

(I notice Jonathan Blow didn't have a problem with this aspect of C++ as
his new language hasn't addressed that: you still have to work out where
functions start and end by analysing a bunch of syntax see if it matches
the pattern for the start of a function instead of the keyword just
telling you.)

--
bart

Juha Nieminen

unread,
Jul 11, 2018, 3:43:40 AM7/11/18
to
Bart <b...@freeuk.com> wrote:
>> Why should it write "(10,20,30,40)"?
>
> Because that's the default output for that type in this language? The
> same as you might get in Python or Ruby in Javascript; the details will
> vary but you will get the values 10, 20, 30, and 40 printed out in some
> form and in that order.

A language like C++ isn't intended to dictate to the programmer what the
text format of something like a list of numbers should be. This especially
given that for consistency it would also need to support "std::cin >> v;"
which becomes a mess given in how many ways that can fail.

> You can write a printlist() routine for a generic list to get it
> displayed as you want.

So can you in C++.

> (How would a debugger for C++ display such a vector?)

That's up to the debugger, not up to the C++ standard.

>> Fragile... What exactly is it that you want? For the compiler to guess
>> using AI what you *really* wanted to say, even though it's not syntactically
>> correct?
>
> I'm saying it is fragile.
>
> What are we declaring here? Some sort of flexible, ie. expandable array
> of a specific type? You can express that in C with a tweak in the syntax:
>
> int v[flex] = {10,20,30,40};
>
> Of course, 'flex' arrays would need to be implemented. The point is that
> such syntax for them is more robust and also tidier (and more consistent
> with existing arrays) than the C++ where such things have to be
> implemented using its language building features. And the syntax for
> invoking those has limitations.

I have no idea what you are talking about, or what it has anything to do
with a language syntax being "fragile". I suspect you have no idea either.

Juha Nieminen

unread,
Jul 11, 2018, 4:01:24 AM7/11/18
to
Vir Campestris <vir.cam...@invalid.invalid> wrote:
> Back when C was invented the return type should have been last. After
> all, it's the last thing you'll need from the function. But it wasn't.

By that same logic the type of a variable should also come after the
name of the variable. (After all, there are language that work like that.)

C++ is complex enough. Maybe we should at least *try* to minimize the
different number of ways to write the same thing, unless there's a
very good reason to add an alternative. Purely cosmetic reasons are
not enough.

(And yes, backwards compatibility ought to be retained for practical
purposes. If you want to create an entirely new language, nothing is
stopping you.)

bol...@cylonhq.com

unread,
Jul 11, 2018, 5:19:42 AM7/11/18
to
On Tue, 10 Jul 2018 23:11:04 +0100
Vir Campestris <vir.cam...@invalid.invalid> wrote:
>On 10/07/2018 10:48, bol...@cylonHQ.com wrote:
>> You ever read the STL source code? Its enough to make anyone weep. There's
>> no reason a similar library (albeit without the templating) couldn't be
>> written in C and then the application code using it would look a lot tidier.
>
>The whole point of the standard TEMPLATE library is the templates.

They don't make that much difference to the application programmer. The C
equivalent would be something like:

struct vector *vectorCreate(enum type *type);
int vectorAdd(struct vector *vec, void *value);
int vectorErase(struct vector *vec, int pos);

struct map *mapCreate(enum type keytype, enum type valtype);
int mapAdd(struct map *map, void *key, void *value);

or something like that where a negative return value would be an error and
>= 0 would be an array position. I'm sure there are many similar libraries
out there already and in fact the berkeley DB library which ships with every
version of unix I've ever used, allows you to do something similar anyway,
albeit with a somewhat complicated API since its a lightweight DB , not just
a collection.

bol...@cylonhq.com

unread,
Jul 11, 2018, 5:26:35 AM7/11/18
to
On Tue, 10 Jul 2018 17:44:38 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>It's rvalue-qualified so the machinery can be used to construct a menu
>in a single expression, like this (it's my actual code at the moment):
>
>
> $with( gui_ext::Auto_parent{ *this } )

Wtf is "$with" ? Is this C++ or Perl or have you been messing about with
macros?

> {
> using namespace gui_ext::menu_data;
> const auto& menubar = *new gui_ext::Menu_bar{
> Itemlist{}
> << (Sub{ "App" }
> << Text_item{ 0, "Blah" }
> << Text_item{ 0, "Blah blah" }
> << Separator{}
> << Text_item{ Cmd::app_exit, "Exit" })
> << (Sub{ "Help" }
> << Text_item{ 0, "Help" }
> << Separator{}
> << Text_item{ Cmd::help_about, "About" }),
> [this]( const int id ) { on_menuitem_picked( id ); }
> };
>
> ...
>
>
>In between the resulting FLTK menu bar and the pure data Itemlist's <<
>machinery, is a generator class Menu_bar that translates the hierarchy
>of menu items to FLTK menu text paths, for FLTK menu creation. Yes, it's

Congratulations. You've added things to a menu bar in a complicated and no
doubt highly inefficient under the hood way.

Ian Collins

unread,
Jul 11, 2018, 5:27:19 AM7/11/18
to
On 11/07/18 21:19, bol...@cylonHQ.com wrote:
> On Tue, 10 Jul 2018 23:11:04 +0100
> Vir Campestris <vir.cam...@invalid.invalid> wrote:
>> On 10/07/2018 10:48, bol...@cylonHQ.com wrote:
>>> You ever read the STL source code? Its enough to make anyone weep. There's
>>> no reason a similar library (albeit without the templating) couldn't be
>>> written in C and then the application code using it would look a lot tidier.
>>
>> The whole point of the standard TEMPLATE library is the templates.
>
> They don't make that much difference to the application programmer.

They make a huge difference to the application programmer, that's why we
use them...

--
Ian.

bol...@cylonhq.com

unread,
Jul 11, 2018, 6:22:39 AM7/11/18
to
No they don't, they just make code more concise. And if you do anything
complicated with templates beyond just using the STL you eventually end up
having to use specialisation and/or typeid() sprinkled around your code when
you get down to the point where types have to processed individually which
is little different to what you'd have to do in C from the start.

Ian Collins

unread,
Jul 11, 2018, 6:25:31 AM7/11/18
to
Do I? That's good to know.

--
Ian.

Paavo Helde

unread,
Jul 11, 2018, 6:52:01 AM7/11/18
to
On 11.07.2018 12:19, bol...@cylonHQ.com wrote:
> On Tue, 10 Jul 2018 23:11:04 +0100
> Vir Campestris <vir.cam...@invalid.invalid> wrote:
>> On 10/07/2018 10:48, bol...@cylonHQ.com wrote:
>>> You ever read the STL source code? Its enough to make anyone weep. There's
>>> no reason a similar library (albeit without the templating) couldn't be
>>> written in C and then the application code using it would look a lot tidier.
>>
>> The whole point of the standard TEMPLATE library is the templates.
>
> They don't make that much difference to the application programmer. The C
> equivalent would be something like:
>
> struct vector *vectorCreate(enum type *type);
> int vectorAdd(struct vector *vec, void *value);
> int vectorErase(struct vector *vec, int pos);
>
> struct map *mapCreate(enum type keytype, enum type valtype);
> int mapAdd(struct map *map, void *key, void *value);
>

Thanks for sharing this horror code from C, sometimes we tend to forget
how much good is there in C++.

With above, a C programmer needs to take great care how to use a
supposedly standard tool - does it need malloc, not malloc, free, not
free, ensure correct types are used in each invocation. The resulting
code cannot be probably refactored in any way because the dangers of
mixing up e.g. int and long are too great.

The main problem with that style is that it does not scale. As each
exemplar takes extra care, the programmer hesitates to add another one
and will rather go to the inefficient and error-prone
array[i_believe_this_is_sufficient_buffer_size] approach instead. Or
alternatively, if he indeed adds the needed number of those containers,
he will have no attention span left for his own work, all his efforts
have just been spent on ensuring that he has used a standard tool correctly.


bol...@cylonhq.com

unread,
Jul 11, 2018, 7:07:47 AM7/11/18
to
On Wed, 11 Jul 2018 22:25:21 +1200
Well perhaps you don't if you're just writing mickey mouse code. Some of us
have had to however.

bol...@cylonhq.com

unread,
Jul 11, 2018, 7:14:42 AM7/11/18
to
On Wed, 11 Jul 2018 13:51:50 +0300
Paavo Helde <myfir...@osa.pri.ee> wrote:
>On 11.07.2018 12:19, bol...@cylonHQ.com wrote:
>> On Tue, 10 Jul 2018 23:11:04 +0100
>> They don't make that much difference to the application programmer. The C
>> equivalent would be something like:
>>
>> struct vector *vectorCreate(enum type *type);
>> int vectorAdd(struct vector *vec, void *value);
>> int vectorErase(struct vector *vec, int pos);
>>
>> struct map *mapCreate(enum type keytype, enum type valtype);
>> int mapAdd(struct map *map, void *key, void *value);
>>
>
>Thanks for sharing this horror code from C, sometimes we tend to forget
>how much good is there in C++.
>
>With above, a C programmer needs to take great care how to use a
>supposedly standard tool - does it need malloc, not malloc, free, not
>free, ensure correct types are used in each invocation. The resulting

An API as above is not going to allocate containers on the stack so some sort
of free() will be required even if its wrapped in an API delete function.

>The main problem with that style is that it does not scale. As each
>exemplar takes extra care, the programmer hesitates to add another one
>and will rather go to the inefficient and error-prone
>array[i_believe_this_is_sufficient_buffer_size] approach instead. Or

You might, I wouldn't. I've used these sorts of APIs and I've never had a
problem with them but I imagine someone who's only ever used C++ might
struggle a bit when having to manually handle memory and multiple types.

>alternatively, if he indeed adds the needed number of those containers,
>he will have no attention span left for his own work, all his efforts
>have just been spent on ensuring that he has used a standard tool correctly.

Only if he's a poor programmer.

Juha Nieminen

unread,
Jul 11, 2018, 8:14:37 AM7/11/18
to
bol...@cylonhq.com wrote:
> They don't make that much difference to the application programmer. The C
> equivalent would be something like:
>
> struct vector *vectorCreate(enum type *type);
> int vectorAdd(struct vector *vec, void *value);
> int vectorErase(struct vector *vec, int pos);

There's a huge difference because that "vector" does not know how the
element values should be copied or assigned.

That might work with elementary types and PODs, but once it gets
any more complicated than that, it becomes either a nightmare or
impossible. For example, suppose that the element is a struct
that contains a vector or a map in it (whose elements might
also contain vectors or maps...) memcpy() isn't going to cut
it. It's just going to break the program really badly.

Essentially you would need to replicate constructors, copy
constructors, assignment operators and destructors in C, by
manually passing and storing tons of pointers around (which
don't need to be stored in C++). Yes, I have seen such C
libraries out there. They look horrible, and they are horribly
inefficient (every additional malloc() you do, makes it less
efficient.)

Bart

unread,
Jul 11, 2018, 8:48:12 AM7/11/18
to
On 11/07/2018 13:14, Juha Nieminen wrote:
> bol...@cylonhq.com wrote:
>> They don't make that much difference to the application programmer. The C
>> equivalent would be something like:
>>
>> struct vector *vectorCreate(enum type *type);
>> int vectorAdd(struct vector *vec, void *value);
>> int vectorErase(struct vector *vec, int pos);
>
> There's a huge difference because that "vector" does not know how the
> element values should be copied or assigned.
>
> That might work with elementary types and PODs, but once it gets
> any more complicated than that, it becomes either a nightmare or
> impossible. For example, suppose that the element is a struct
> that contains a vector or a map in it (whose elements might
> also contain vectors or maps...) memcpy() isn't going to cut
> it. It's just going to break the program really badly.

If things are that complicated then I might suggest that neither C++ nor
C is the right language.

Look at CPython for example, which allows all those complex container
types, in spades, and using dynamic typing to boot (so you can have a
vector of ANY mix of types).

But CPython is written in C. Using C++ wouldn't bring much to the table,
since /its/ container types cannot directly be used for those in Python.

> Essentially you would need to replicate constructors, copy
> constructors, assignment operators and destructors in C, by
> manually passing and storing tons of pointers around (which
> don't need to be stored in C++). Yes, I have seen such C
> libraries out there. They look horrible, and they are horribly
> inefficient (every additional malloc() you do, makes it less
> efficient.)

That wouldn't really happen as you wouldn't bother with anything so
complex in C. Either those vectors contain only 'flat' elements that can
simply be allocated or copied as a block, or you have special handling
for the elements /that is part of the application/.

--
bart


bol...@cylonhq.com

unread,
Jul 11, 2018, 10:30:34 AM7/11/18
to
On Wed, 11 Jul 2018 12:14:27 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>bol...@cylonhq.com wrote:
>> They don't make that much difference to the application programmer. The C
>> equivalent would be something like:
>>
>> struct vector *vectorCreate(enum type *type);
>> int vectorAdd(struct vector *vec, void *value);
>> int vectorErase(struct vector *vec, int pos);
>
>There's a huge difference because that "vector" does not know how the
>element values should be copied or assigned.
>
>That might work with elementary types and PODs, but once it gets
>any more complicated than that, it becomes either a nightmare or
>impossible. For example, suppose that the element is a struct
>that contains a vector or a map in it (whose elements might
>also contain vectors or maps...) memcpy() isn't going to cut
>it. It's just going to break the program really badly.

Certainly for complex types you'd have to pass in a function pointer to a
function you wrote that would be called to do the actual copy. The above was
just for example purposes, not a definitive API. However the point is that
for probably 90% of what C++ containers get used for the C equivalent wouldn't
be too much extra work to use.

>don't need to be stored in C++). Yes, I have seen such C
>libraries out there. They look horrible, and they are horribly
>inefficient (every additional malloc() you do, makes it less
>efficient.)

C++ isn't magic - it still ultimately has to allocate memory whether it be
on the stack or heap. That will take the same amount of time as in C.

Bart

unread,
Jul 11, 2018, 1:41:18 PM7/11/18
to
On 11/07/2018 17:51, Stefan Ram wrote:
> Bart <b...@freeuk.com> writes:
>> On 11/07/2018 13:14, Juha Nieminen wrote:
>>> There's a huge difference because that "vector" does not know how the
>>> element values should be copied or assigned.
>> If things are that complicated then I might suggest that neither C++ nor
>> C is the right language.
>
> In object-oriented programming, every object knows how to
> copy itself (this is the responsibility of the assignment
> operator). So, in C++, a vector uses this to copy every
> element.
>
> (I have not read all of the thread, and so I might have
> missed what you two actually were talking about. Sorry!)
>

What I was suggesting is that a program that involves correct handling
of vectors of maps of arrays of structs or whatever, might be better
suited to a scripting language which handles this stuff effortlessly.

Which would leave simpler data structures where a C-style approach of
doing things via function-based libraries or with more application
involvement wouldn't be that much of an imposition.

At least, you can understand such C code at the low-level, as a bunch of
structs and arrays and function calls, even if you don't get the big
picture. That is far less likely with C++.

(I write compilers, interpreters, assemblers and linkers, nowadays using
low-level code; the most sophisticated data structures I use are a hash
table, and an expanding byte buffer. If I was to bring in some of those
heavyweight container types you get with C++, they would probably grind
to a halt.)

Anyway using the default copy mechanism of C++ might not work with
something like this:

typedef struct tag {int a,b,c; struct tag *p, *q;} S;
S x, y;
S *xx, *yy;

How would x = y work? How about xx = yy? A plain shallow copy, as I
understand the default copy to be, may not be sufficient. Or sometimes
it will, and sometimes it won't; it depends! Maybe xx=yy will copy the
pointers but also needs to set something inside *yy.

How much application involvement will there be, and how much will it
depend on default handling of generic struct types?

--
bart

Ian Collins

unread,
Jul 11, 2018, 4:43:50 PM7/11/18
to
Ha, so that's what I do. Very insightful.

--
Ian.

Paavo Helde

unread,
Jul 11, 2018, 4:46:25 PM7/11/18
to
On 11.07.2018 20:41, Bart wrote:
>
> (I write compilers, interpreters, assemblers and linkers, nowadays using
> low-level code; the most sophisticated data structures I use are a hash
> table, and an expanding byte buffer. If I was to bring in some of those
> heavyweight container types you get with C++, they would probably grind
> to a halt.)

So you are saying your systems have troubles with common data structures
which have been in wide use for tens of years - what conclusions we
should draw from this?

> Anyway using the default copy mechanism of C++ might not work with
> something like this:
>
> typedef struct tag {int a,b,c; struct tag *p, *q;} S;
> S x, y;
> S *xx, *yy;
>
> How would x = y work? How about xx = yy? A plain shallow copy, as I
> understand the default copy to be, may not be sufficient. Or sometimes
> it will, and sometimes it won't; it depends! Maybe xx=yy will copy the
> pointers but also needs to set something inside *yy.

In C++ you objects of RAII objects into the class. RAII objects like
std::vector or std::shared_ptr know how to copy themselves, no problem.
In general, one should not put raw pointers into a class, especially if
they own resources, for the reasons you just listed.

The implementation of the low-level classes like std::vector and
std::shared_ptr is more complicated and needs custom constructors,
assignment operators and destructors. Luckily, this work has been done
in the standard library to a large extent already. But if you need more
flexibility you can always define new low-level RAII classes.


bitrex

unread,
Jul 11, 2018, 5:23:50 PM7/11/18
to
On 07/10/2018 09:01 AM, bol...@cylonHQ.com wrote:
> On Tue, 10 Jul 2018 14:37:07 +0200
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>> There are some levels of understanding involved.
>
> Naturally you're conversant with all these levels arn't you.
>
>> I've always disagreed strongly with those who maintain that one who
>> doesn't have 20 years experience in designing cars, can't evaluate a car
>> design with square wheels. Because that problem is obvious. The argument
>> that one is disqualified is a purely associative one, idiotic IMHO,
>> although it must be said that that argument often /works/, when it
>> appeals to authority in a direction that the herd has experience with.
>>
>> But that's not what you're doing here. You're not evaluating on the
>> basis of seeing square wheels or something like that. You're evaluating
>> on the basis of feeling uneasy with new language features, and, it seems
>> to me, on the basis of needing much time to understand unfamiliar
>> combinations of simple features, that involve 3 or more relationships.
>
> If you want to use a car analogy - you're the sort of designer who doesn't
> actually drive but thought it would be a great idea to have everything
> controlled by a touchscreen. After all, touchscreen interfaces are common
> now , everyone uses them and it requires less components. Unfortunately you
> completely forgot that when driving one can't look at a touchscreen and with
> zero haptic feedback they're next to useless in that situation so even changing
> a radio channel or setting the air con becomes impossible unless topped.
> Technology for its own sake.
>
> Similarly with your code - you write code to impress and use as much cutting
> edge syntax as you can because its there, not because its appropriate or would
> be maintainable in the wild. Syntax for its own sake.
>

it's perfectly understandable there's no mystery to it you're just not
familiar with modern C++. it is what it is. Stop whining

bitrex

unread,
Jul 11, 2018, 5:29:52 PM7/11/18
to
On 07/10/2018 08:37 AM, Alf P. Steinbach wrote:
> On 10.07.2018 13:12, Juha Nieminen wrote:
>> bol...@cylonhq.com wrote:
>>> How exactly does any of this syntatic masturbation solve any
>>> problems? Because
>>> lets remember, a programming language is just a tool, not an end in
>>> itself.
>>
>> Indeed. Syntactic tools should be used when they make sense, and make
>> the code
>> clearer, easier to use, safer, more understandable, or all of the above.
>> Using them just for the sake of it, especially if it makes the code
>> harder
>> to understand, and especially if there are clearer alternatives, makes no
>> sense.
>
> There are some levels of understanding involved.
>
> I've always disagreed strongly with those who maintain that one who
> doesn't have 20 years experience in designing cars, can't evaluate a car
> design with square wheels. Because that problem is obvious. The argument
> that one is disqualified is a purely associative one, idiotic IMHO,
> although it must be said that that argument often /works/, when it
> appeals to authority in a direction that the herd has experience with.
>
> But that's not what you're doing here. You're not evaluating on the
> basis of seeing square wheels or something like that. You're evaluating
> on the basis of feeling uneasy with new language features, and, it seems
> to me, on the basis of needing much time to understand unfamiliar
> combinations of simple features, that involve 3 or more relationships.
>
> That's like the close-voters on Stack Overflow who decide that someone's
> question must be off-topic or nonsense because they don't understand it,
> sometimes even in the face of very clear answers to that question.
>
> That is, they're using their inflated opinions of their own competence,
> to infer from their own lack of understanding that the question must be
> nonsense. Or else they would have understood it, surely. Their reaction
> is not to ask about anything, for what could there be to ask about?, and
> besides that would be outside their comfort zone; they instead simply
> vote to close, to get this to them affronting nonsense out of the way.
>
>
> Cheers!,
>
> - Alf (social focus mode)

I invite the "syntactic masturbation" crowd to look at this snipped of
Erlang and explain how this works on first examination:

<https://csdl-images.computer.org/mags/ic/2007/05/figures/w50901.gif>

that's it though. That's the language, sorry. If you don't like it and
think it's obtuse then GTFO write basic or something.

bitrex

unread,
Jul 11, 2018, 5:39:15 PM7/11/18
to
On 07/10/2018 08:37 AM, Alf P. Steinbach wrote:
> On 10.07.2018 13:12, Juha Nieminen wrote:
>> bol...@cylonhq.com wrote:
>>> How exactly does any of this syntatic masturbation solve any
>>> problems? Because
>>> lets remember, a programming language is just a tool, not an end in
>>> itself.
>>
>> Indeed. Syntactic tools should be used when they make sense, and make
>> the code
>> clearer, easier to use, safer, more understandable, or all of the above.
>> Using them just for the sake of it, especially if it makes the code
>> harder
>> to understand, and especially if there are clearer alternatives, makes no
>> sense.
>
> There are some levels of understanding involved.
>
> I've always disagreed strongly with those who maintain that one who
> doesn't have 20 years experience in designing cars, can't evaluate a car
> design with square wheels. Because that problem is obvious. The argument
> that one is disqualified is a purely associative one, idiotic IMHO,
> although it must be said that that argument often /works/, when it
> appeals to authority in a direction that the herd has experience with.

The joke-variant is that you don't need to be a master chef to know bad
food when you taste it.

But "appeal to authority" has to be a valid tactic sometimes because an
"authority" whose opinions are never more useful or informed than the
average person is not actually an authority in anything.

The reason "appeals to authority" often fall flat is that the appeal is
usually to the wrong authority, and in the US at least there are no
shortage of authorities in, generously, one or two topics who feel that
their credentials in those one or two topics give them authority to
speak with more authority than any layman, in any topic at all.

Bart

unread,
Jul 11, 2018, 5:59:37 PM7/11/18
to
On 11/07/2018 21:46, Paavo Helde wrote:
> On 11.07.2018 20:41, Bart wrote:

> So you are saying your systems have troubles with common data structures
> which have been in wide use for tens of years - what conclusions we
> should draw from this?

No trouble, just that I found them unnecessary. Those programs I write
are very fast by taking some care with design rather than doing anything
sophisticated. The main data structure is a singly-linked list - using a
raw pointer. And most searches are sequential.

> In C++ you objects of RAII objects into the class. RAII objects like
> std::vector or std::shared_ptr know how to copy themselves, no problem.
> In general, one should not put raw pointers into a class, especially if
> they own resources, for the reasons you just listed.

At a certain level of language it's not something that you want to
unduly worry about. And it seems that with C++ there are is a lot /more/
to keep in mind.

I tend to code either at the C level where I'm using simple data
structures, or a couple of levels up using dynamic code which makes a
lot of this stuff painless to use (you rarely use pointers at all for
example).

So it is interesting to observe how it works between those two points
with C++. The only thing I might envy is to be able to use sophisticated
data handling but also have it fast (dynamic code is slow).

> The implementation of the low-level classes like std::vector and
> std::shared_ptr is more complicated and needs custom constructors,
> assignment operators and destructors. Luckily, this work has been done
> in the standard library to a large extent already. But if you need more
> flexibility you can always define new low-level RAII classes.

That's the last thing I'd want to do when writing applications. I tend
to adopt the KISS principle. (I do know what RAII stands for; what it
means is another matter and another thing to worry about that I don't need.)


--
bart

Bart

unread,
Jul 11, 2018, 6:12:38 PM7/11/18
to
On 11/07/2018 18:49, Stefan Ram wrote:
> Bart <b...@freeuk.com> writes:
>> At least, you can understand such C code at the low-level, as a bunch of
>> structs and arrays and function calls, even if you don't get the big
>> picture. That is far less likely with C++.
>
> You don't need to understand C++ code at the low level
> because you can understand it at the high level.

I have from time to time needed to convert algorithms from one language
to another (usually one of mine).

When that original language is C, that offers enough problems of its own
(what with over-enthusiastic use of the macro system and such).

With C++ however, that takes the difficulties to a whole new level.

Also, even when I don't want to understand the source code or translate
it, but just use the program as an already compiled library [from my
language], then with C I can eventually manage to use such a library,
given docs and an interface usually as a .h C header file.

But when an interface is specified in C++ code, then forget it! (I was
never able to use APIs such as GDI+ or DirectDraw for those reasons.)

--
bart

woodb...@gmail.com

unread,
Jul 11, 2018, 7:02:15 PM7/11/18
to
On Wednesday, July 11, 2018 at 3:46:25 PM UTC-5, Paavo Helde wrote:
> On 11.07.2018 20:41, Bart wrote:
> >
> > (I write compilers, interpreters, assemblers and linkers, nowadays using
> > low-level code; the most sophisticated data structures I use are a hash
> > table, and an expanding byte buffer. If I was to bring in some of those
> > heavyweight container types you get with C++, they would probably grind
> > to a halt.)
>
> So you are saying your systems have troubles with common data structures
> which have been in wide use for tens of years - what conclusions we
> should draw from this?
>
> > Anyway using the default copy mechanism of C++ might not work with
> > something like this:
> >
> > typedef struct tag {int a,b,c; struct tag *p, *q;} S;
> > S x, y;
> > S *xx, *yy;
> >
> > How would x = y work? How about xx = yy? A plain shallow copy, as I
> > understand the default copy to be, may not be sufficient. Or sometimes
> > it will, and sometimes it won't; it depends! Maybe xx=yy will copy the
> > pointers but also needs to set something inside *yy.
>
> In C++ you objects of RAII objects into the class. RAII objects like
> std::vector or std::shared_ptr know how to copy themselves, no problem.
> In general, one should not put raw pointers into a class, especially if
> they own resources, for the reasons you just listed.

I disagree with that. There's a BufferCompressed type here:
https://github.com/Ebenezer-group/onwards/blob/master/Buffer.hh

,around line 509, that has several owning raw pointers. This
post by Howard Hinnant:
https://stackoverflow.com/questions/38780596/how-to-handle-constructors-that-must-acquire-multiple-resources-in-an-exception#38780597

was helpful to me.


Brian
Ebenezer Enterprises - Enjoying programming again.
http://webEbenezer.net

Alf P. Steinbach

unread,
Jul 11, 2018, 8:12:49 PM7/11/18
to
On 11.07.2018 23:23, bitrex wrote:
> On 07/10/2018 09:01 AM, bol...@cylonHQ.com wrote:
>> On Tue, 10 Jul 2018 14:37:07 +0200
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>> [snip]

boltar know I don't see his messages, and that as far as I know the last
of his identities that I killfiled was the third, but he uses "you" in
his posting responding to mine, as if he were writing to me.

In his interactions with me he's mostly concentrated on the personal,
discussing imagined motivations and so on, as he does above.

Thanks for letting me see that, bitrex. I have a relatively clean view
of clc++, like a street view, but it's worth knowing about the sewers
underneath. Lest one should fall into a manhole for forgetting about it.


Cheers!,

- Alf

Ian Collins

unread,
Jul 12, 2018, 12:50:03 AM7/12/18
to
On 12/07/18 09:59, Bart wrote:

> That's the last thing I'd want to do when writing applications. I tend
> to adopt the KISS principle. (I do know what RAII stands for; what it
> means is another matter and another thing to worry about that I don't need.)

So you prefer ignoring code that prevents resource leaks? Good plan.

Which is the more simple approach, using a standard object to manage
reference counting and resource management or doing it all by hand?

Which is less error prone?

--
Ian

Paavo Helde

unread,
Jul 12, 2018, 1:15:40 AM7/12/18
to
So you have decided to ignore the single most useful and productive
feature provided by C++. No wonder you find C++ complicated and clumsy.

The KISS principle is fine. What could be more simpler than drop a
std::vector in your class and not having to worry about how it resizes
and destroys itself.

bol...@cylonhq.com

unread,
Jul 12, 2018, 6:25:51 AM7/12/18
to
Using every syntatic construct he can simply because its there to achieve
something that could have been achieved easily using other methods is not
clever, its showboating. And no one wants to work with programmers like that.

Bart

unread,
Jul 12, 2018, 6:26:24 AM7/12/18
to
On paper C++ sounds great. A lot of its features seem natural
progressions in language design, especially when the start point is C.
(I do a bit of language design and some areas are starting to encroach
on C++ territory, but I'm trying to rein it in.)

But strangely I'm loath to use it even though it's a free download. And
that's not all due to its including nearly all the worst features of C
which I'm not a big fan of.

Imagine the following rough progression of languages from lower to
higher level (here based on increasing sophistication of list-handling,
say):

ASM....C........C++........Python
^ ^

I mentioned I normally use two languages that fit in roughly where I've
marked (both home-made, but that doesn't affect the principle).

If I wanted to just have 'drop-in' vectors, I'd use the second language.
If I need things to be fast and efficient and with precise control of
data structures, I'd use the first.

C++ will give me some convenience of those drop-in vectors, but it's not
as convenient as the second language, and its code not as simple or as
clear. The resulting executable will usually be much faster, but then
the build process is considerably more cumbersome. It lacks spontaneity.

I would quite like to be able to use some of the stuff in C++ but there
are just too many things that put me off.


--
bart

alfs...@showboater.central.com

unread,
Jul 12, 2018, 6:30:27 AM7/12/18
to
On Thu, 12 Jul 2018 02:12:41 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>On 11.07.2018 23:23, bitrex wrote:
>> On 07/10/2018 09:01 AM, bol...@cylonHQ.com wrote:
>>> On Tue, 10 Jul 2018 14:37:07 +0200
>>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
>>> [snip]
>
>boltar know I don't see his messages, and that as far as I know the last

I can make you see my messages if I want, its quite easily done as you have
discovered previously and now. But I'd forgotten you had such a fragile ego and
can't handle criticism. I imagine you're either self employed or work in a
university since I can't imagine many companies hiring someone who deliberately
writes complex code and isn't interested in hearing any negative feedback.

>In his interactions with me he's mostly concentrated on the personal,
>discussing imagined motivations and so on, as he does above.

I obviously hit the nail on the head or you wouldn't have killfiled me.

>Thanks for letting me see that, bitrex. I have a relatively clean view
>of clc++, like a street view, but it's worth knowing about the sewers
>underneath. Lest one should fall into a manhole for forgetting about it.

Ah, a superiority complex too. What an asset you'd be to any development
team! Not.

Alf P. Steinbach

unread,
Jul 12, 2018, 8:13:49 AM7/12/18
to
On 12.07.2018 12:30, boltar alias alfs...@showboater.central.com wrote:
> On Thu, 12 Jul 2018 02:12:41 +0200

That's now the fourth Boltar identity I've killfiled.

- Alf


Rosario19

unread,
Jul 12, 2018, 8:24:04 AM7/12/18
to
On Thu, 12 Jul 2018 11:26:20 +0100, Bart wrote:

> ASM....C........C++........Python

possibly i'm alone on this
i not find many pro (only i like cpu simple instructions)
but i like C++ until cpu instruction
more than Axiom or any other language that not start to some cpu
instruction

pooro...@has.no.clue.com

unread,
Jul 12, 2018, 10:38:39 AM7/12/18
to
On Thu, 12 Jul 2018 14:13:40 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
You seem to be under the impression that I have a limited supply of them and
eventually I'll run out. Do you understand how usenet works?

bitrex

unread,
Jul 12, 2018, 10:58:35 AM7/12/18
to
the nerds who labored 100,000 man-hours in their momma's basement
putting all those new syntactic constructs and features in the more
recent dialects of C++ didn't go to all that work for people _not_ to
use them!

The manuals to the new standards in the section on automatic return type
deduction and rvalue references and move semantics didn't come with an
addendum that says "This is the dark black magic part! Don't do this
_too_ much or you gonna burn out the compiler!! and nobody will like you!"

bol...@cylonhq.com

unread,
Jul 12, 2018, 11:19:59 AM7/12/18
to
On Thu, 12 Jul 2018 10:58:24 -0400
You use a feature when it makes things simpler, not when it complicates the
code.

Alf P. Steinbach

unread,
Jul 12, 2018, 11:23:30 AM7/12/18
to
On 12.07.2018 16:38, pooro...@has.no.clue.com wrote:
> [idiocy redacted]

5th Boltar identity killfiled.

Hergen Lehmann

unread,
Jul 12, 2018, 12:15:11 PM7/12/18
to
Am 12.07.2018 um 16:58 schrieb bitrex:

> The manuals to the new standards in the section on automatic return type
> deduction and rvalue references and move semantics didn't come with an
> addendum that says "This is the dark black magic part! Don't do this
> _too_ much or you gonna burn out the compiler!! and nobody will like you!"

But they don't say "you have to use this" or "this is preferred over the
traditional syntax" either.

Think of your colleagues! Use well-known, proven semantics and
algorithms, unless the more exotic ones represent a significant advantage.

bitrex

unread,
Jul 12, 2018, 12:30:05 PM7/12/18
to
I think if you want to make a counterpoint it would be fair to provide
examples of what you consider to be a high-performance non-showboaty
codebase that approaches your ideals or else it's hard to say what we're
actually talking about. "I know what I like and this ain't it" is a hard
proposition to argue with

C++ is all about performance that's why you use features like move
semantics and template gobblediegook. If one prefers less "complicated"
code (to whatever ideal standard of just-simple-enough-but-no-simpler
one is making the comparison to) there are many compiled and interpreted
languages that many people seem to like better; Python, C#, Go, Rust,
and so forth.

I know a couple of those too and I also use them they're the right tool
for the job a lot of times. There's no law against it it's not a
marriage. Many have tried to make the "simplicity of an interpreted
language with the speed of C++"-language but few have seemed to succeed
so far.

I invite you to look at the alternatives and while they may seem much
more inviting at first glance, when you actually start trying to
leverage them to make super-clean non-showoffy simple code that also has
C-like performance some of the stuff you end up with isn't going to be
that much more parsable than what we've seen here.

bitrex

unread,
Jul 12, 2018, 12:40:31 PM7/12/18
to
I like to give my colleagues the benefit of the doubt and assume that if
they have written some code that doesn't seem too off the wall but does
some "exotic" stuff I don't understand at first glance they probably
have a reason for it and they aren't just trying to make my life
difficult as the show-off C++ mastah. If they were trying to make my
life difficult they'd format the code in a circular shape and have it
calculate its own area

the example posted wasn't particularly exotic compared to code you see
in the wild or Modern C++ Design by Andrei Alexandrescu, thumb through a
copy if you don't believe me. If they're all bad people welp I guess
that's the way it is...

bitrex

unread,
Jul 12, 2018, 12:46:48 PM7/12/18
to
Damn son you could've read Modern C++ Design or a recent copy of
Effective C++ and understood that snippet forwards and backwards no
problem at all in the time you spent bitchin' about it.

Daniel

unread,
Jul 12, 2018, 1:35:04 PM7/12/18
to
On Thursday, July 12, 2018 at 12:30:05 PM UTC-4, bitrex wrote:
>
> C++ is all about performance

with the notable exception of streams, numeric from/to text conversion, the potential for aliasing to stop the compiler from doing some optimizations, and a few other things.

Daniel

woodb...@gmail.com

unread,
Jul 12, 2018, 2:29:38 PM7/12/18
to
We don't have static exceptions either. I'm afraid that
2020 ++C will not bring them either.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Tim Rentsch

unread,
Jul 12, 2018, 10:40:06 PM7/12/18
to
bitrex <us...@example.net> writes:

> [...]

> The _runtime_ component of C++, the actual stuff that gets parsed
> directly into object code, is really nothing much more than a mild
> superset of C, [...]

"a mild superset". That's a good one. :)

Melzzzzz

unread,
Jul 12, 2018, 11:01:40 PM7/12/18
to
It is better to say that C++ has compatibility with C, then speaking in
terms of superset.

--
press any key to continue or any other to quit...

keepgo...@what.a.hero.com

unread,
Jul 13, 2018, 5:23:28 AM7/13/18
to
On Thu, 12 Jul 2018 17:23:23 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
Keep going mate! :)

bol...@cylonhq.com

unread,
Jul 13, 2018, 5:32:20 AM7/13/18
to
On Thu, 12 Jul 2018 12:29:54 -0400
bitrex <us...@example.net> wrote:
>I think if you want to make a counterpoint it would be fair to provide
>examples of what you consider to be a high-performance non-showboaty
>codebase that approaches your ideals or else it's hard to say what we're

Sorry, I have better things to do than rewrite Alfs code. You'll just have
to believe me when I say I believe its needlessly overcomplicated.

>C++ is all about performance that's why you use features like move
>semantics and template gobblediegook. If one prefers less "complicated"

I'm not saying new features shouldn't be used. But there's a time and place.
For example he just loves to use this sort of syntax (look back in his posts):

auto func() -> int { }

Why? The point of auto is when you DON'T know the return type. What is so
wrote with just writing: int func() { }. Answer - nothing. He just likes to
show off.

>languages that many people seem to like better; Python, C#, Go, Rust,
>and so forth.

I also use python. C# only runs on windows and Go and Rust seem to be just
wannabe C++'s which isn't a good enough reason to use them. You also forgot 'D'
which is another.

>leverage them to make super-clean non-showoffy simple code that also has
>C-like performance some of the stuff you end up with isn't going to be
>that much more parsable than what we've seen here.

If I need C like performance I'll just use C. It has the advantage (unlike C++)
of being almost entirely explicit - what you see is what you get. Unlike in
C++ where all sorts of hidden things can happen and can sometimes be missed
even by professionals when looking at code.

Alf P. Steinbach

unread,
Jul 13, 2018, 6:50:15 AM7/13/18
to
On 13.07.2018 11:23, "Boltar" wrote:
> On Thu, 12 Jul 2018 17:23:23 +0200
[redacted]

6th Boltar identity killfiled.

"Boltar" REALLY likes to troll by posting with fake identities to clc++.
So maybe there are two nutcases with that behavior pattern in clc++.

Manfred

unread,
Jul 13, 2018, 9:45:52 AM7/13/18
to
On 7/10/2018 5:44 PM, Alf P. Steinbach wrote:
>> OK, I'll ask the obvious.
>>
>> Why (*this).Itemlist instead of this->Itemlist
>>
>> I'm assuming the explicit refernce to this is due to some template
>> weirdness.  Otherwise the question becomes, why explicitly specify
>> "this"?
>
> This is a should-have-been-simple-really forwarding to the base class
> `operator<<`, which is rvalue-qualified.
>
> The rvalue qualification means that it must be called on an rvalue
> expression. I would be happy to learn of some better way than the
> `move(*this)`. It was the first I could think of, but it is very very
> ugly to my eyes... So, suggestions/ideas/knowledge very welcome.

One alternative could be non-member operators << :

struct Itemlist
{

std::string description() const
{
// do something
return "";
}
};

template<class Item>
static Itemlist&& operator << (Itemlist&& lhs, Item item)
{
return std::move(lhs);
}


struct Sub
: Text_item
, Itemlist
{
Sub(const std::string& text)
: Text_item(0, text)
{ }

};

template< class Item >
static Sub&& operator << (Sub&& lhs, Item item )
{
return static_cast<Sub&&>( operator << (
static_cast<Itemlist&&>(lhs), item ) );
}

It still insists on requiring std::move(lhs) on the operator << for
Itemlist, but at least it gets rid of the really ugly

> move( *this ).Itemlist::operator<<( item )

bolta...@kennel.com

unread,
Jul 13, 2018, 10:49:34 AM7/13/18
to
On Fri, 13 Jul 2018 12:50:06 +0200
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
No, its just amusing to watch your pomposity. :)

Daniel

unread,
Jul 13, 2018, 12:10:03 PM7/13/18
to
On Friday, July 13, 2018 at 5:32:20 AM UTC-4, bol...@cylonhq.com wrote:
>
> C# only runs on windows

No. My music player Roon consists of a Roon Server running on a dedicated linux box and a Roon app running on an ipad mini, all using C#.

Daniel

Vir Campestris

unread,
Jul 13, 2018, 5:28:22 PM7/13/18
to
On 11/07/2018 11:22, bol...@cylonHQ.com wrote:
> No they don't, they just make code more concise. And if you do anything
> complicated with templates beyond just using the STL you eventually end up
> having to use specialisation and/or typeid() sprinkled around your code when
> you get down to the point where types have to processed individually which
> is little different to what you'd have to do in C from the start.

I think you must be using them wrongly.

Andy

Vir Campestris

unread,
Jul 13, 2018, 6:27:59 PM7/13/18
to
On 11/07/2018 15:30, bol...@cylonHQ.com wrote:
> Certainly for complex types you'd have to pass in a function pointer to a
> function you wrote that would be called to do the actual copy. The above was
> just for example purposes, not a definitive API. However the point is that
> for probably 90% of what C++ containers get used for the C equivalent wouldn't
> be too much extra work to use.

Oh, but it would. Those smart pointers, for example, mean you don't have
to remember to call free when you've finished with the memory. You just
let the smart pointer go out of scope, and the target vanishes. And this
happens down all your obscure error paths too.

And the copy - once you've taught the object how to copy itself nobody
else has to mess about with memcpy(target, source, sizeof(type)) then
fix any embedded pointers.

Andy

Juha Nieminen

unread,
Jul 14, 2018, 2:48:18 PM7/14/18
to
Bart <b...@freeuk.com> wrote:
>> That might work with elementary types and PODs, but once it gets
>> any more complicated than that, it becomes either a nightmare or
>> impossible. For example, suppose that the element is a struct
>> that contains a vector or a map in it (whose elements might
>> also contain vectors or maps...) memcpy() isn't going to cut
>> it. It's just going to break the program really badly.
>
> If things are that complicated then I might suggest that neither C++ nor
> C is the right language.

What do you mean? The above scenario is *trivial* in C++:

//--------------------------------
struct A
{
std::vector<int> v1, v2;
};

struct B
{
std::vector<A> a1, a2;
};

std::vector<B> bVector;
//--------------------------------

C++ was *designed* to handle the above situation just right,
without much hassle.

C wasn't.

Bart

unread,
Jul 14, 2018, 6:07:51 PM7/14/18
to
I seized on the word 'maps' and envisioned something more elaborate than
your example, involving structs, vectors and maps in various arrangements.

But even with something like the above, I don't think this is quite as
trivial as you suggest. A scripting language (even mine which is lower
level than most) really could handle this stuff trivially and would
probably run rings around any C++ code.

(I tried to put something together that uses your data structures (not
C++ and not static), see example in sig; this uses flex strings rather
than int vectors for some extra interest.)

>
> C wasn't.

You tend to adapt code, algorithms and data structures to suit the
language. Unless those arrays absolutely need random access and need to
be counted arrays (ie. carrying their length with them), then in C I
might write them as simply-linked lists, especially with elements more
involved than simple ints.

I've been using a language at the C level for decades without needing
all the stuff in C++ (although string handlng is a PITA). For higher
level requirements I've worked out how to balance low-level static code
and scripting code.

--
bart

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

import sys

record A = (var v1, v2)
record B = (var a1, a2)

proc start=
bVector := ()

to random(10) do # random(10) returns values 0 to 9
x := ()
to random(10) do
x append:= A(randomstring(), randomstring())
od
bVector append:= B(x, tail(x))
od

forall x in bvector do
println =x.a1
println =x.a2
od
end

function randomstring=
x:=""
to random(10) do
x +:= random('A'..'Z')
od
return x
end
----------------------------------------------
Output:

X.A1= ((S,LZFR),(JECVY,HRFNL),(VZXLIH,F),(GMCOGQ,))
X.A2= ((JECVY,HRFNL),(VZXLIH,F),(GMCOGQ,))
X.A1= ((ZAMOPYE,O),(TZQDFTW,PR),(NLVJUX,ZXDFBH),(SEBQW,OO))
X.A2= ((TZQDFTW,PR),(NLVJUX,ZXDFBH),(SEBQW,OO))
X.A1= ((VI,AADD),(YX,WV),(VTVKXW,IRZFHMIY))
X.A2= ((YX,WV),(VTVKXW,IRZFHMIY))
X.A1=
((VHSEYW,PQQIWI),(JUDUZRCFI,JLZIS),(NSDFAK,CZJCF),(XNKJRIS,AUUTPQC),(D,PI),(FBOIVYB,),(,HW),(N
C,EBTEVT))
X.A2=
((JUDUZRCFI,JLZIS),(NSDFAK,CZJCF),(XNKJRIS,AUUTPQC),(D,PI),(FBOIVYB,),(,HW),(NC,EBTEVT))
X.A1= ((JY,JDTBLPI),(,HNGD))
X.A2= ((,HNGD))
X.A1= ((TY,NGKTQPI))
X.A2= ()
X.A1= ((GGCYRO,),(D,N),(ETB,EUQVF),(UKS,QUXR),(,PVR))
X.A2= ((D,N),(ETB,EUQVF),(UKS,QUXR),(,PVR))

Ian Collins

unread,
Jul 14, 2018, 7:12:29 PM7/14/18
to
On 15/07/18 10:07, Bart wrote:
>
> I've been using a language at the C level for decades without needing
> all the stuff in C++ (although string handlng is a PITA). For higher
> level requirements I've worked out how to balance low-level static code
> and scripting code.

Some of us need performance from higher level code...

--
Ian.

Bart

unread,
Jul 14, 2018, 8:16:18 PM7/14/18
to
That's where getting the balance right comes in.

I guess you're familiar with getting tasks done by a combination of
shell scripts plus actual compiled programs that do the real work. There
wouldn't be much advantage in writing everything in 100% C or C++.

Well I believe in doing rather more using scripting. That still leaves
plenty of work for a fast language somewhat more advanced than C, but it
might not need to go quite as far as C++ does.

(My main text editor for last few years has been written in 100%
interpreted code. You don't notice until you get to 5 or 10-million line
files then some operations are slow, but then they use simple
techniques. And I've used other editors (such as gedit on Linux, which I
guess is not interpreted) which can be slow enough to be almost unusable.)

--
bart

Melzzzzz

unread,
Jul 14, 2018, 9:08:49 PM7/14/18
to
Where have you found 5 or 10-million line files ;)?

Ian Collins

unread,
Jul 14, 2018, 9:24:36 PM7/14/18
to
On 15/07/18 12:16, Bart wrote:
> On 15/07/2018 00:12, Ian Collins wrote:
>> On 15/07/18 10:07, Bart wrote:
>>>
>>> I've been using a language at the C level for decades without needing
>>> all the stuff in C++ (although string handlng is a PITA). For higher
>>> level requirements I've worked out how to balance low-level static code
>>> and scripting code.
>>
>> Some of us need performance from higher level code...
>
> That's where getting the balance right comes in.
>
> I guess you're familiar with getting tasks done by a combination of
> shell scripts plus actual compiled programs that do the real work. There
> wouldn't be much advantage in writing everything in 100% C or C++.

For real time control software, performance is crucial. If you don't
meet your performance budget, things fail in horrible ways or you have
to blow your hardware budget on faster processors.

> Well I believe in doing rather more using scripting.

Belief is irrelevant when you have budgets to meet!

--
Ian.


bitrex

unread,
Jul 15, 2018, 12:17:21 AM7/15/18
to
Without metaprogramming (and all the stuff that utilizes template
metaprogramming like the STL) C++ really isn't much to write home about
in the year of our Lord 2018.

Paavo Helde

unread,
Jul 15, 2018, 3:48:40 AM7/15/18
to
Well, that's a point in favor of C++, it provides much more flexible
means for expressing the subject area concepts directly in the language.

> Unless those arrays absolutely need random access and need to
> be counted arrays (ie. carrying their length with them), then in C I
> might write them as simply-linked lists, especially with elements more
> involved than simple ints.

A linked list with each node allocated dynamically is about the worst
data structure one can come up with, performance-wise. It is slow when
constructed, slow when destructed, and slow when traversed (because of
memory hopping).

There are very few usage cases for std::list in C++, and I haven't
encountered any in ~20 years of C++ programming. Each time either
std::deque or std::vector has been a better fit.


> I've been using a language at the C level for decades without needing
> all the stuff in C++ (although string handlng is a PITA). For higher
> level requirements I've worked out how to balance low-level static code
> and scripting code.

In a scripting language the language designer has taken all the
technical decisions (are objects stored by value or allocated
dynamically, are they garbage-collected, reference-counted or something
else; is the copy deep or shallow, or maybe copy-on-write (shallow copy
emulating deep copy), how automatic are the conversions, are the data
structures multithread-safe or single-threaded, etc.

This means that a scripting language is much less flexible than C++
where one can choose all such points as the best fit for each usage
case. Of course greater flexibility means greater responsibility and
more brain cycles to figure out the correct solution.

Typically a scripting language makes some more or less sensible choices
and hopes these are good enough for a large audience. E.g. Python has
everything dynamically allocated and reference-counted, lots of global
mutable state, not multithread-safe (requiring a global lock), shallow
copy (creating multiple references into the data structures which may be
hard to manage). As a result it is pretty easy to use and hack in simple
cases, a bit harder to work out long-term robust solutions, and the
performance is overall not so great. Because of the last point, Python
needs extensions written in C or C++ for performance-critical work, e.g.
NumPy, Keras+Tensorflow etc.

I have nothing against the scripting languages, I'm developing and
maintaining one myself. However, I would not like to write code in one,
because of limited expressiveness, lack of strict type checking and less
thorough error checking in general. Ironically, the C language shares
all these points, so to me it appears more similar to scripting
languages than to C++.



Alf P. Steinbach

unread,
Jul 15, 2018, 6:48:33 AM7/15/18
to
On 15.07.2018 09:48, Paavo Helde wrote:
>
> There are very few usage cases for std::list in C++, and I haven't
> encountered any in ~20 years of C++ programming. Each time either
> std::deque or std::vector has been a better fit.

I found one usage a few days ago: to create and hold on to a set of
instances of the item type, dynamically.

Because nothing's invalidated by inserting into a `std::list`.

Well I used a `std::forward_list`, since it would never be traversed.


Cheers!,

- Alf

Bart

unread,
Jul 15, 2018, 7:55:16 AM7/15/18
to
Test outputs or sometimes test inputs of various programs. Or sometimes
files containing textual data.

Is this really so exceptional?

Obviously normal source files and such will be a few thousand lines at most.

--
bart

Bart

unread,
Jul 15, 2018, 7:57:05 AM7/15/18
to
How about deadlines?

--
bart


Bart

unread,
Jul 15, 2018, 9:09:30 AM7/15/18
to
On 15/07/2018 08:48, Paavo Helde wrote:
> On 15.07.2018 1:07, Bart wrote:

>> be counted arrays (ie. carrying their length with them), then in C I
>> might write them as simply-linked lists, especially with elements more
>> involved than simple ints.
>
> A linked list with each node allocated dynamically is about the worst
> data structure one can come up with, performance-wise. It is slow when
> constructed, slow when destructed, and slow when traversed (because of
> memory hopping).

(Interesting. I have several compilers and an assembler which both make
heavy use of linked lists (and in intricate ways: see below).

The assembler can process input at up to 4 million lines per second, two
of the compilers can approach one million lines per second.

It would be great if using C++ container types could make them even faster!)

> There are very few usage cases for std::list in C++, and I haven't
> encountered any in ~20 years of C++ programming. Each time either
> std::deque or std::vector has been a better fit.

That wouldn't suit my styling of coding. In one compiler, the main
symbol table record includes these fields (expressed as C):

struct _strec {
...
struct _strec* owner; // up
struct _strec* deflist; // down
struct _strec* deflistx; // down (points to end of list)
struct _strec* nextdef; // hoz (singly linked)
struct _strec* nextdupl; // hoz (these 2 doubly linked)
struct _strec* prevdupl; //
...
struct _strec* nextmacro; // hoz (singly linked)
...

The record can be linked in up to 7 different ways to other records (how
would std::list work here?). Your deque and vector suggestions are akin
to how I used to do this in interpreted code:

global record strec=
...
var owner
var deflist
var dupllist
...

Tidier (and more convenient since those lists are random access and
contain their bounds), but the implementation was much slower. I would
imagine the equivalent workings inside C++ would also have overheads
above those of using bare linked lists.


> and the
> performance is overall not so great. Because of the last point, Python
> needs extensions written in C or C++ for performance-critical work, e.g.
> NumPy, Keras+Tensorflow etc.

In the case of NumPy, Python is being used as a front end to a
scientific numeric library written in a faster language. I understand
that it works well (as scientists find it easier to write Python than C++).

(For my purposes, I find Python and its ecosystem to be large, sprawling
and cumbersome; NumPy was so difficult to install at one time that the
simplest suggestion was to install Anaconda, a 1GB download that
included NumPy. However C++ guys would feel right at home...)

The scripting language I use is lower level, less dynamic, and usually
executes more briskly (than Python) without having to use accelerators.

> I have nothing against the scripting languages, I'm developing and
> maintaining one myself. However, I would not like to write code in one,
> because of limited expressiveness,

That's not often a criticism of scripting languages. Usually you can
express exactly what you like and leave to it to the implementation to
do the work needed.

Mine for example can use Pascal-style sets and set constructors,
something I've rarely seen anywhere else:

identstarter := ['A'..'Z', 'a'..'z', '_', '$']
identbody := identstarter + ['0'..'9] - ['Z'] #exclude Z
if c in identstarter then ...

I expect both Python and C++ have a Set implementation so powerful that
it can do anything - except construct simple sets as easily as above).

--
bart

woodb...@gmail.com

unread,
Jul 15, 2018, 1:22:51 PM7/15/18
to
I think that's an understatement:
https://blog.famzah.net/2016/09/10/cpp-vs-python-vs-php-vs-java-vs-others-performance-benchmark-2016-q3/

Python was 18 times slower than ++C.

> Because of the last point, Python
> needs extensions written in C or C++ for performance-critical work, e.g.
> NumPy, Keras+Tensorflow etc.
>
> I have nothing against the scripting languages, I'm developing and
> maintaining one myself. However, I would not like to write code in one,
> because of limited expressiveness, lack of strict type checking and less
> thorough error checking in general.

They are known for getting something working fast, but
then you are stuck with either biting the bullet and
converting to another language or digging a deeper hole.


Brian
Ebenezer Enterprises - Enjoying programming again.
http://webEbenezer.net

Ian Collins

unread,
Jul 15, 2018, 4:30:25 PM7/15/18
to
What about them? Scripting languages don't scale as well as compiled
languages for big projects with a big team.

--
Ian

Bart

unread,
Jul 15, 2018, 6:08:16 PM7/15/18
to
I would have thought the opposite. It depends on the design of the
scripting language, but it is possible for one module to be
independently compiled and run (if compilation is even a requirement)
without all modules needing to be combined in a linker-like process into
a monolithic binary before any change can be tested.

That also means individuals can develop, run and test their own scripts
without knowing what others are doing.

And when I used the technique a lot, the language was an add-on to the
application, and users - even 1000s if I had that many - could write
scripts to interact with their copy of the application, without the
application needing rebuilding each time.

(In early days it was also a necessity for script files to reside on
floppy and to only load and run the one that was necessary for a
specific command. In that form, the program could grow indefinitely with
hundreds of modules store on dozens of floppies. Modules that could be
written by different people. That's why I say it is more scalable.)

Anyway isn't something like Javascript used on quite a big scale?

--
bart


Scott Lurndal

unread,
Jul 15, 2018, 7:51:09 PM7/15/18
to
Vir Campestris <vir.cam...@invalid.invalid> writes:
>On 11/07/2018 15:30, bol...@cylonHQ.com wrote:
>> Certainly for complex types you'd have to pass in a function pointer to a
>> function you wrote that would be called to do the actual copy. The above was
>> just for example purposes, not a definitive API. However the point is that
>> for probably 90% of what C++ containers get used for the C equivalent wouldn't
>> be too much extra work to use.
>
>Oh, but it would. Those smart pointers, for example, mean you don't have
>to remember to call free when you've finished with the memory. You just
>let the smart pointer go out of scope, and the target vanishes. And this
>happens down all your obscure error paths too.

For which there is an inevitable cost. In a recent project, we ripped
out all the smart pointers because they had a huge performance impact. The
code was almost twice as fast after elimination of the smart pointers.

Alf P. Steinbach

unread,
Jul 15, 2018, 9:48:05 PM7/15/18
to
No offense intended, just that it might help you to hear me thoughts here.

It seems likely to me that

* the smart pointers were not the performance problem, but measuring a
debug build gave nonsense data, and

* when the code evolves further the decision to remove smart pointers is
going to bite someone, then, very hard in the ass. Uh, arse. Well, let's
say the "behind", if that's PC. ;-)


Cheers!,

- Alf

Juha Nieminen

unread,
Jul 16, 2018, 1:19:58 AM7/16/18
to
Bart <b...@freeuk.com> wrote:
> I seized on the word 'maps' and envisioned something more elaborate than
> your example, involving structs, vectors and maps in various arrangements.

Well, freely substitute std::vector with std::map in my example. It doesn't
get any more complicated.

Even if you were to use your own custom dynamic data container, its use
still doesn't have to become any more complicated since the language gives
you the tools to make it as simple to use as std::vector and std::map.

> But even with something like the above, I don't think this is quite as
> trivial as you suggest. A scripting language (even mine which is lower
> level than most) really could handle this stuff trivially and would
> probably run rings around any C++ code.

How? A scripting language would probably be slower.

Besides, the comparison was to C (and the use of generic data containers
there), not to some other languages.

Juha Nieminen

unread,
Jul 16, 2018, 1:26:18 AM7/16/18
to
Paavo Helde <myfir...@osa.pri.ee> wrote:
> There are very few usage cases for std::list in C++, and I haven't
> encountered any in ~20 years of C++ programming. Each time either
> std::deque or std::vector has been a better fit.

It's extremely rare, but sometimes std::list *is* the most convenient
(and, possibly, even most efficient) solution to a problem.

Consider, for example, a video game where an enemy shoots tons of
projectiles. These projectiles may hit scenery and objects pretty
much at random, at any moment, with no specific order. The enemy also
spawns new projectiles almost constantly. Therefore new projectiles
are being spawned at a regular basis, and they disappear (and thus
should be removed) pretty much at random.

As it turns out, std::list is the most convenient data container
for this. All the projectiles are put into one, and at each frame you
traverse the list and update their positions and check for collisions.
Every time a projectile collides with something and is destroyed, you
can conveniently remove it from the list.

In this situation being able to remove the projectile object from the
current position in the list in O(1) is both convenient and efficient
(and may well make up for the slight inefficiency of the memory
allocations needed for the list elements.)

The same cannot be efficiently done with a std::vector or std::deque,
where removing the object from it is an O(n) operation.
It is loading more messages.
0 new messages