Tuesday, July 10, 2018

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

Ian Collins <ian-news@hotmail.com>: Jul 10 03:25PM +1200

On 10/07/18 02:37, Bart wrote:
> 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.
 
Which is what most of C++14 did...
 
> 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.
 
> 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 <nospam@thanks.invalid>: Jul 10 06:29AM

> 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.
boltar@cylonHQ.com: Jul 10 09:48AM

On Mon, 9 Jul 2018 21:52:35 +0100
>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.
 
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.
boltar@cylonHQ.com: Jul 10 09:55AM

On Mon, 9 Jul 2018 17:56:11 +0200
 
> 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 <nospam@thanks.invalid>: Jul 10 11:12AM

> 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 <nospam@thanks.invalid>: Jul 10 11:20AM

> 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 <bc@freeuk.com>: Jul 10 01:24PM +0100

On 10/07/2018 12:20, Juha Nieminen wrote:
 
> 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" <alf.p.steinbach+usenet@gmail.com>: Jul 10 02:37PM +0200

On 10.07.2018 13:12, Juha Nieminen wrote:
> 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)
Juha Nieminen <nospam@thanks.invalid>: Jul 10 12:58PM

>> 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?
 
> 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?
boltar@cylonHQ.com: Jul 10 01:01PM

On Tue, 10 Jul 2018 14:37:07 +0200
>There are some levels of understanding involved.
 
Naturally you're conversant with all these levels arn't you.
 
>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.
Juha Nieminen <nospam@thanks.invalid>: Jul 10 06:32AM

> "Jonathan Blow: "C++ is a weird mess""
 
> https://www.gamesindustry.biz/articles/2018-07-02-jonathan-blow-c-is-a-weird-mess
 
"There are only two kinds of languages: the ones people complain about and
the ones nobody uses." - Bjarne Stroustrup
SG <s.gesemann@gmail.com>: Jul 10 02:41AM -0700

On Tuesday, July 10, 2018 at 1:15:09 AM UTC+2, Lynn McGuire wrote:
 
> https://www.gamesindustry.biz/articles/2018-07-02-jonathan-blow-c-is-a-weird-mess
 
> Just because one is correct does not mean that one's solutions are any
> better.
 
True. And C++ being a weird mess seems to be well-accepted:
 
"Within C++, there is a much smaller and cleaner language
struggling to get out." -- Bjarne Stroustrup
 
Though, I see Blow's language with mixed feelings, too. There are
some nice things about it (super fast compiler, incredibly powerful metaprogramming) but a lot of the design decisions just seem weird.
For example, in one of his videos he says destructors in C++ were a
bad idea and in another video he introduces a special pointer syntax
for an "owning" pointer which frees memory automatically. That just
seems like cognitive dissonance to me. While I think there are
points to be made for certain things to be core language features
rather than library-provided tools (I'm looking at you, std::tuple &
std::variant), I think unique ownership pointers aren't one of them
and the better design is to make the language powerful enough
(--> destructors) to create things like unique_ptr as a library. If
you have destructors, you get more than just convenient memory
management without introducing a rather limited core-language feature.
 
Let's see how this Jai turns out ...
 
Cheers!
sg
Bart <bc@freeuk.com>: Jul 10 11:41AM +0100

On 10/07/2018 10:41, SG wrote:
> struggling to get out." -- Bjarne Stroustrup
 
> Though, I see Blow's language with mixed feelings, too. There are
> some nice things about it (super fast compiler,
 
According to the LLVM link on this page (I won't link direct to the
youtube video so as not to bring down the tone of this group):
 
https://inductive.no/jai/
 
the compiler is not so fast at the moment as it relies on LLVM to do the
code generation.
 
That example uses a 34KLoc example program, and takes some 2.5 seconds
source to executable (I think the version using a C compiler back-end is
somewhat faster).
 
The 'front-end', what he calls compiling to byte-code, is about 0.2
seconds, so that's pretty fast (about 170Klps). But even if that was
all, it wouldn't be 'super-fast'.
 
(My own compiler projects at the moment are considerably faster than
even that front end, and the compilers are not themselves optimised
other. But I would still hesitate to call that super-fast; I think I'd
reserve that for 1Mlps and above. I've only occasionally breached that.)
 
Interesting BTW that he's using a Windows machine for development (one
using SSD too as is mentioned at one point; mine just has a regular
HDD), rather than the usual Linux. To hear people on these groups tell
it, Windows is hopeless for software development.
 
> Let's see how this Jai turns out ...
 
The language snippets I saw didn't really grab me. I can't get a sense
of its 'shape' or identity. I think we need to see more complete programs.
 
--
bart
Thiago Adams <thiago.adams@gmail.com>: Jul 10 05:39AM -0700

On Tuesday, July 10, 2018 at 6:41:20 AM UTC-3, SG wrote:
...
> For example, in one of his videos he says destructors in C++ were a
> bad idea and in another video he introduces a special pointer syntax
> for an "owning" pointer which frees memory automatically.
 
I didn't find the videos.Do you have the links?
Bo Persson <bop@gmb.dk>: Jul 10 02:48PM +0200

On 2018-07-10 01:14, Lynn McGuire wrote:
 
> Just because one is correct does not mean that one's solutions are any
> better.
 
> Lynn
 
I think the real insight is
 
"As a project gets bigger the longer it takes to make changes, Blow
explains, and the nature of programming means that significant amounts
of time get dedicated to "what is essentially busywork."
 
without him fully realizing that.
 
 
I have seen the "new system"-syndrome in real life:
 
We had a group of guys starting to build a new service from scratch in
C# on a bunch of empty Windows servers. The management soon saw that
they churned out code twice as fast as us old guys on the mainframe
(with tons of interfaces to existing systems).
 
So, apparently, .NET was the silver bullet to solve the productivity
problem for the company!
 
Unfortunately, a year later the C# guys started on a second project and
soon realized that now they would also have to consider existing systems
and adapt their new code to what they already had.
 
And they also had to hire techies to run and maintain the servers now
that their system was in 24/7 production.
 
Not long after that, the productivity gap had mysteriously disappeared.
 
 
So, starting from scratch might look promising initially, but...
 
 
Bo Persson
Bart <bc@freeuk.com>: Jul 10 01:54PM +0100

On 10/07/2018 13:39, Thiago Adams wrote:
>> bad idea and in another video he introduces a special pointer syntax
>> for an "owning" pointer which frees memory automatically.
 
> I didn't find the videos.Do you have the links?
 
 
Try: https://inductive.no/jai/
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 10 03:05AM +0200

Il 09/07/2018 21:04, Alf P. Steinbach ha scritto:
 
>     template< class Number, class = enable_if_t<
> is_integral_v<Number> >
>     auto mod( Number a, Number b ) -> Number { return a%b; }
 
sorry, I feel dumb but as the topic is not my cup of tea ...
I see 3 open angular < and two closed >.
 
Surely it is trivial typo, but the third > would simply be
after the consecutive closed (with a space not to be parsed
as >> op. True ?
Sorry for the futile remark, but ... well, I'm not that sure
where it should go.
 
 
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
red floyd <no.spam@its.invalid>: Jul 09 06:17PM -0700

On 07/09/2018 01:49 PM, Vir Campestris wrote:
 
> std::array
 
> (as I'm sure you know, but the OP might not.)
 
> Andy
 
Thanks. Typos happen.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 10 10:41AM +0200

On 10.07.2018 03:05, Soviet_Mario wrote:
> consecutive closed (with a space not to be parsed as >> op.   True ?
> Sorry for the futile remark, but ... well, I'm not that sure where it
> should go.
 
Yes, just place it at the end. The spaces are not really necessary in
C++11 and later.
 
--------------------------------------------------------------------
#include <type_traits> // std::is_integral_v
#include <utility> // std::enable_if_t
using namespace std;
 
template<class Number, class = enable_if_t<is_integral_v<Number>>>
auto mod( Number a, Number b )
-> Number
{ return a%b; }
 
#include <iostream>
int main()
{
const int a = mod( 13, 5 );
#ifdef TEST
const double b = mod( 13.0, 5.0 ); //! Won't compile.

No comments: