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

Structured binding considered harmful

681 views
Skip to first unread message

jacobnavia

unread,
Mar 12, 2020, 7:14:10 PM3/12/20
to
Here is one exemple of "structured binding" from the paper of Filipek:

int main() {
// Initialize a map table.
const std::map<std::string, int> mapCityPopulation {
{ "Beijing", 21'707'000 },
{ "London", 8'787'892 },
{ "New York", 8'622'698 }
};

for (auto&[city, population] : mapCityPopulation)
std::cout << city << ": " << population << '\n';
}

Within the for statement the variables "city" and "population" will be
bound automatically to the corresponding fields of the map.

Cute isn't it?

Before, in the old times, you would have to write:
(I cite the book of Filipek page 29)

<quote>

Consider a function that returns two results in a pair:

std::pair<int, bool> InsertElement(int el) { ... }

You can write:
auto ret = InsertElement(...)
And then refer to ret.first or ret.second. However, referring to values
as .first or .second is also not expressive - you can easily confuse the
names, and it’s hard to read.
<end quote>

Yes, maybe is not "expressive". There is an easy work around though, as
Filipek shows:

<quote>
Alternatively you can leverage std::tie which will unpack the tuple/pair
into local variables:
int index { 0 };
bool flag { false };
std::tie(index, flag) = InsertElement(10);
Such code might be useful when you work with std::set::insert which
returns std::pair:std::set<int> mySet;

std::set<int>::iterator iter;
bool inserted { false };

std::tie(iter, inserted) = mySet.insert(10);
if (inserted)
std::cout << "Value was inserted\n";

As you see, such a simple pattern - returning several values from a
function - requires several lines of code.
<end quote>

Yes, several lines of code that is easily read by anyone and by existing
tools.

And here awe arrive at the essence of why C++ is going into endless
complexity: a desire to have "cute" constructs and save some seconds to
the programmer typing the new code in.

Nothing will be said about the need to reprogram all tools that read C++
code to accept the new stuff, the need to figure out all ramifications
of the new construct, etc etc.

Because the consequences are terrible when you do not have a 1 to 1
correspondence between the names in the bracket enclosed list, and the
class whose fields will be "bound" to those names.


Even WORST:

What happens when the class is modified to have a new field?
All the structured binding constructs have to be modified to add the new
field, and if you miss one crashes and bugs will inevitably happen.

All of this is not necessary using the old syntax that was more verbose
but MUCH SAFER and robust.

MINDLESS COMPLXITY FOR COMPLEXITY's SAKE, with no improvement to
anything useful.

All the tools have to be rewritten to accomodate this nonsense, what is
not easy since you have to get the definition of the class object that
can be anywhere else, in another header file or whatever!

What is the end result?

A new useless construct has been added to the language that serves no
purpose other than saving some seconds when typing C++.

GREAT!

Maciej Sobczak

unread,
Mar 13, 2020, 3:46:57 AM3/13/20
to
> Even WORST:
>
> What happens when the class is modified to have a new field?

Presumably that new field has some meaning that should not be neglected up-front.

> All the structured binding constructs have to be modified

And for some this is actually a feature, because without extremely costly review of existing code, the compiler will *automatically* tell you where are all the places that might require your attention. If neglecting the new field in any given place would result in a bug, you have all such potential places reported to you for free.
This is a similar reasoning to the capability of detecting that switch statements become incomplete when the new enumeration value is added to the enum type definition.

Interestingly:
Some people believe that having the "default" branch makes their code robust to such changes.
Others believe that it is the capability to detect *statically* that existing switch statements became incomplete and require attention makes their code even more robust.

Of course, there will be concrete examples for either way, but that's why it is good to have a choice *at the call site*.
So, if you want your code to be "robust" by making it indifferent to newly added fields, write your code that way.
But if you want your code to be "robust" by making it auto-detect structural changes and get your attention to potential problems, then write your code the other way.

I don't claim that any of these two definitions of "robust" is better, but I've seen real cases to support either one.

And I think that your actual problem is that you were given a choice. :-)

> All the tools have to be rewritten to accomodate

Yes, this is a disadvantage of introducing new features to the language.
But not all tools need to be rewritten - only those that want to stay competitive on the market. Or you also have a choice of standardizing on a smaller language subset, to stay with existing tools - this possibility was already discussed.

--
Maciej Sobczak * http://www.inspirel.com

Öö Tiib

unread,
Mar 13, 2020, 12:40:29 PM3/13/20
to
On Friday, 13 March 2020 01:14:10 UTC+2, jacobnavia wrote:
> Here is one exemple of "structured binding" from the paper of Filipek:
>
> int main() {
> // Initialize a map table.
> const std::map<std::string, int> mapCityPopulation {
> { "Beijing", 21'707'000 },
> { "London", 8'787'892 },
> { "New York", 8'622'698 }
> };
>
> for (auto&[city, population] : mapCityPopulation)
> std::cout << city << ": " << population << '\n';
> }
>
> Within the for statement the variables "city" and "population" will be
> bound automatically to the corresponding fields of the map.
>
> Cute isn't it?

No, doesn't compile, since necessary #includes are missing.
Someone posting this trash in anything-goes-newsgroup is fine,
but if it is really in book then burn it and use "Filipek" like
mild profanity.

The constructs like you seem to imply do not compile as well.
Try:

std::string city;
int population;
for (std::bind(city, population) : mapCityPopulation)
std::cout << city << ": " << population << '\n';

It does not parse, syntax error. Also you do not really post
what you would like to see so I'm confused what is your
suggestion.


Sam

unread,
Mar 13, 2020, 11:08:49 PM3/13/20
to
jacobnavia writes:

> Even WORST:
>
> What happens when the class is modified to have a new field?
> All the structured binding constructs have to be modified to add the new
> field, and if you miss one crashes and bugs will inevitably happen.

Bullshit.

The code will fail to compile. And after fixing every return value, you'll
go back to your happy place.

Even decades-old Makefiles will automatically recompile everything that
pulls in the modified declaration, recompiling everything, and having your
compiler tell you everything you need to fix.

Please read a good C++ book, and try it yourself, before spewing this
nonsense again.


jacobnavia

unread,
Mar 14, 2020, 3:59:58 AM3/14/20
to
Le 14/03/2020 à 04:08, Sam a écrit :
> jacobnavia writes:
>
>> Even WORST:
>>
>> What happens when the class is modified to have a new field?
>> All the structured binding constructs have to be modified to add the
>> new field, and if you miss one crashes and bugs will inevitably happen.
>
> Bullshit.
>
> The code will fail to compile. And after fixing every return value,
> you'll go back to your happy place.
>


I said:

All the structured binding constructs have to be modified

Then you say:

Bullshit

and in the next sentence you confirm what I have said.

> The code will fail to compile. And after fixing every return value,
> you'll go back to your happy place.

And you seem to ignore the contradiction!

Too much C++ affects reasoning capacity?

Or is it simply that ypu are answering out of "C++ nationalism", i.e
Trump's "My country right or wrong". as "My computer language right or
wrong"

As most other answers to my critique, you just seem to be touched
emotionally and your answers are emotional:

"spewing nonsense", etc.

Keep calm. We aren't speaking about your mother or about your country.
We are diuscussing a computer language feature. That's all.

Breath deeply and now answer me: Why is this new construct necessary?

Wasn't the old way of writing them easier and more robust?

THAT was my question. Please answer it.

jacobnavia

unread,
Mar 14, 2020, 4:05:58 AM3/14/20
to
Le 13/03/2020 à 17:40, Öö Tiib a écrit :
> On Friday, 13 March 2020 01:14:10 UTC+2, jacobnavia wrote:
>> Here is one exemple of "structured binding" from the paper of Filipek:
>>
>> int main() {
>> // Initialize a map table.
>> const std::map<std::string, int> mapCityPopulation {
>> { "Beijing", 21'707'000 },
>> { "London", 8'787'892 },
>> { "New York", 8'622'698 }
>> };
>>
>> for (auto&[city, population] : mapCityPopulation)
>> std::cout << city << ": " << population << '\n';
>> }
>>
>> Within the for statement the variables "city" and "population" will be
>> bound automatically to the corresponding fields of the map.
>>
>> Cute isn't it?
>
> No, doesn't compile, since necessary #includes are missing.

Yes, I missed the includes. Here they are:

#include <map>
#include <iostream>
#include <string>


> Someone posting this trash in anything-goes-newsgroup is fine,
> but if it is really in book then burn it and use "Filipek" like
> mild profanity.
>

You make a mountain out of a simple c ut/paste error.

> The constructs like you seem to imply do not compile as well.
> Try:
>
> std::string city;
> int population;
> for (std::bind(city, population) : mapCityPopulation)
> std::cout << city << ": " << population << '\n';
>
> It does not parse, syntax error. Also you do not really post
> what you would like to see so I'm confused what is your
> suggestion.

I would say the compiler have to parse that by using the right
standard... Maybe you didn't se the standard to C++20

In any case you did NOT answer my question, since you can't apparently.
Or you did not see it whatever. Here is it AGAIN:

WHAT IS THE PURPOSE OF THIS "ENHANCEMENT"?

Why it is so important that you HAVE to add it to an already unbearible
complex language?

Why can't the old way of writing that code be maintained SIMPLIFYING the
language?

THAT was my point that you did not even mention!


jacobnavia

unread,
Mar 14, 2020, 4:10:34 AM3/14/20
to
Le 13/03/2020 à 08:46, Maciej Sobczak a écrit :
>> All the structured binding constructs have to be modified
> And for some this is actually a feature, because without extremely costly review of existing code, the compiler will*automatically* tell you where are all the places that might require your attention. If neglecting the new field in any given place would result in a bug, you have all such potential places reported to you for free.

But the old way of writing it in C++14 doesn't have those pitfalls!

Even if you add 30 new fields, since the binding is done "manually" it
will continue to work unmodified. You just declare two new variables and
assign to them the values of the fields you want!

WHY this "enhancement" if the old way is more robust?

THAT is my point!!!

Here we have a new way of doing the same thing that is in many cases
WORST as the current one and will be added anyway, making an already
very complex language EVEN MORE COMPLEX!

And THAT was my point!

Öö Tiib

unread,
Mar 14, 2020, 6:19:30 AM3/14/20
to
On Saturday, 14 March 2020 10:05:58 UTC+2, jacobnavia wrote:
> Le 13/03/2020 à 17:40, Öö Tiib a écrit :
> > On Friday, 13 March 2020 01:14:10 UTC+2, jacobnavia wrote:
> >> Here is one exemple of "structured binding" from the paper of Filipek:
> >>
> >> int main() {
> >> // Initialize a map table.
> >> const std::map<std::string, int> mapCityPopulation {
> >> { "Beijing", 21'707'000 },
> >> { "London", 8'787'892 },
> >> { "New York", 8'622'698 }
> >> };
> >>
> >> for (auto&[city, population] : mapCityPopulation)
> >> std::cout << city << ": " << population << '\n';
> >> }
> >>
> >> Within the for statement the variables "city" and "population" will be
> >> bound automatically to the corresponding fields of the map.
> >>
> >> Cute isn't it?
> >
> > No, doesn't compile, since necessary #includes are missing.
>
> Yes, I missed the includes. Here they are:
>
> #include <map>
> #include <iostream>
> #include <string>
>
>
> > Someone posting this trash in anything-goes-newsgroup is fine,
> > but if it is really in book then burn it and use "Filipek" like
> > mild profanity.
> >
>
> You make a mountain out of a simple c ut/paste error.

Mea culpa. I just tried to mimic back your unmerciful style when
discussing a tool. Lets try a bit more calmly?

>
> > The constructs like you seem to imply do not compile as well.
> > Try:
> >
> > std::string city;
> > int population;
> > for (std::bind(city, population) : mapCityPopulation)
> > std::cout << city << ": " << population << '\n';
> >
> > It does not parse, syntax error. Also you do not really post
> > what you would like to see so I'm confused what is your
> > suggestion.
>
> I would say the compiler have to parse that by using the right
> standard... Maybe you didn't se the standard to C++20

It can't compile, it is syntax error in C++20. Range based for is:
for ( range_declaration : range_expression ) loop_statement
Call of function template std::bind is not a declaration.
I just had to point it out since majority of your post contained
such blunders.

> In any case you did NOT answer my question, since you can't apparently.
> Or you did not see it whatever. Here is it AGAIN:
>
> WHAT IS THE PURPOSE OF THIS "ENHANCEMENT"?

Sorry, I lost question in the pile of rant that felt incorrect. My
eyes are just accustomed to notice defects and in defective stuff
my mind stops searching any meaning.
I see no purpose of that particular enchantment. I continue writing:

for (auto const& e : mapCityPopulation)
std::cout << e.first << ": " << e.second << '\n';

When navigating within iterated element is too repetitive, verbose
and/or abstract (it isn't in that toy example but can be) then
I name these using local variables:

for (auto const& e : mapCityPopulation) {
char const* city = e.first.c_str();
int population = e.second;
std::cout << city << ": " << population << '\n';
}

I do same in every other place in code where something looks too
repetitive, verbose and/or abstract so it hurts readability.

> Why it is so important that you HAVE to add it to an already unbearible
> complex language?

My guess is that it is perhaps sabotage of wormtongues from monster
software companies with task to deteriorate the language to non-
useful. I disliked the language changes in C++17 as well. But I may
be wrong.

> Why can't the old way of writing that code be maintained SIMPLIFYING the
> language?
>
> THAT was my point that you did not even mention!

World is what it is. For me it is more important what we,
programmers can do to mitigate the issues. Actual market for
C++ has been in serious raise (in my experience) but skilled
specialists are hard to find and so half of people programming in
it can't actually comprehend it.

Sam

unread,
Mar 14, 2020, 10:09:45 AM3/14/20
to
jacobnavia writes:

> Le 14/03/2020 à 04:08, Sam a écrit :
>> jacobnavia writes:
>>
>>> Even WORST:
>>>
>>> What happens when the class is modified to have a new field?
>>> All the structured binding constructs have to be modified to add the new
>>> field, and if you miss one crashes and bugs will inevitably happen.
>>
>> Bullshit.
>>
>> The code will fail to compile. And after fixing every return value, you'll
>> go back to your happy place.
>>
>
>
> I said:
>
> All the structured binding constructs have to be modified
>
> Then you say:
>
> Bullshit
>
> and in the next sentence you confirm what I have said.

You're still full of bullshit. The bullshit part is the one that says "and
if you miss one crashes and bugs will inevitably happen".

That's the bullshit.

The reality is that if you miss one, the code won't compile, at all.

Try to learn C++, one of these days, ok?

> > The code will fail to compile. And after fixing every return value,
> > you'll go back to your happy place.
>
> And you seem to ignore the contradiction!

You don't understand, Einstein. The code will fail to compile. If it can't
compile, it can't "crash" and cause "bugs" to "inevitably happen".

> Wasn't the old way of writing them easier and more robust?

No, it wasn't. If you suddenly figured out that a function or a method
needed to return two or more discrete values, instead of one, the new way is
faster, less typing, and less error-prone.

> THAT was my question. Please answer it.

I just did: you're still full of bullshit.

jacobnavia

unread,
Mar 14, 2020, 1:32:55 PM3/14/20
to
Le 14/03/2020 à 15:09, Sam a écrit :
> You're still full of bullshit. The bullshit part is the one that says
> "and if you miss one crashes and bugs will inevitably happen".
>
> That's the bullshit.

Dear Sam:

I am referring to the page 35 of

<https://drive.google.com/file/d/1W0Em5ioHiBdIG3LeXqpwla4wcPxvOBKq/view?usp=sharing>

In that page we have the description of the general interface of
structurezd binding with some arbitrary class, that he calls UserEntry.

<quote>
class UserEntry {
public:
void Load() { }
std::string GetName() const { return name; }
unsigned GetAge() const { return age; }
private:
std::string name;
unsigned age { 0 };
size_t cacheEntry { 0 }; // not exposed
};
<end quote>

We have here then a class with 3 fields, "name", "age", and another
called "cacheEntry" that is NOT EXPOSED to the structured binding interface.

To be able to specify in a "structured binding" the alias for the fields
you have to define (nothing less than ) 3 things:

1: get<N>,
2: std::tuple_size and
3: std::tuple_element

Here is an exemple:

<quote>
// with if constexpr:
template <size_t I> auto get(const UserEntry& u) {
if constexpr (I == 0) return u.GetName();
else if constexpr (I == 1) return u.GetAge();
}
namespace std {
template <> struct tuple_size<UserEntry>:integral_constant<size_t,2> {};
template <> struct tuple_element<0,UserEntry> { using type = std::string; };
template <> struct tuple_element<1,UserEntry> { using type=unsigned; };
}
<end quote>

As you see the "get" template receives an index that IS HARDCODED TO THE
INDEX OF THE FIELD, and any changes by INSERTING A NEW FIELD will make
those indexes silently access the WRONG FIELD, since if you add a field
at the beginning, it will become the zeroeth field of course.

Will it compile?

Well, if you insert a std::string at the beginning it WILL COMPILE since
the type of the first field is unchaged: it was std::string and REMAINS
std::string.

Now, let me make two remarks here:

1: We are speaking of just syntactic sugar for avoiding using two new
variables and some typing... To avoid that you type MUCH MORE NOW since
you have to define those 3 items I mentioned above and that is surely a
LOT of more typing.

2: Note that the names are "bound" to the fields of an anonymous object
created by the compiler? They are (excuse for this) what we would write in C

#define name tmp.name
#define age tmp.age

where the "tmp" is a name give,n by the compiler and invisible to the
program as written.

Is that name captured by a lambda expression?

Since you told me I do not know C++ I will leave to you the answer to
that question, since you obviously know more C++ than me.

Coming back to the problem at hand, we see that to save a trivial typing
(Mr Tib proposed it in this thread)
for (auto const& e : mapCityPopulation) {
char const* city = e.first.c_str();
int population = e.second;
std::cout << city << ": " << population << '\n';
}

there is more to type and figure out, and a complex interface of several
templates and definitions needs to be constructed!

What has been gained by adding this enormous complexity?

That is my question, that remains. I hope that I answered yours:

YES, THE CODE WILL SILENTLY COMPILE WRONG STUFF.

Q.E.D

Sam

unread,
Mar 14, 2020, 6:33:22 PM3/14/20
to
jacobnavia writes:

> As you see the "get" template receives an index that IS HARDCODED TO THE
> INDEX OF THE FIELD, and any changes by INSERTING A NEW FIELD will make those
> indexes silently access the WRONG FIELD,

Which will now be a completely different class, and this will guarantee a
compilation error, until this is fixed.

A new field will change the size of the tuple binding.

This means that all existing code that uses structured bindings for these
values from the function that returns it, like:

auto &[name, age]=some_function_that_returns_UserEntry();

If and when a third field gets added to this UserEntry, and gets exposed via
structured bindings, this specific binding will now FAIL. Guaranteed. No
chance of miscompilation. Even if the name field is now index #1, and age is
index #2 and the new field is the same data type as name, and index 0.

So, there are now at least two different reasons why this will cause a
compilation error, and why the original claim is still 100% bullshit.

> since if you add a field at the
> beginning, it will become the zeroeth field of course.
>
> Will it compile?

No.

> Well, if you insert a std::string at the beginning it WILL COMPILE since the
> type of the first field is unchaged: it was std::string and REMAINS
> std::string.

None of the existing structured bindings will compile. They're all binding
two elements, instead of three.

Fail.

But what about pre-C++17 code that uses `std::get` to bind individual
elements?

Well, as the old joke goes: "Doctor, it hurts when I move my arm this way".
"Well, don't move your arm this way, then".

With a

auto &[value1, value2]=

structured binding, you are guaranteed a compilation failure when a new
binding gets added or removed. That's one preventative measure that's the
simplest solution. Use structured bindings this way, and any new bindings is
a guaranteed compilation failure.

Now, what about code that uses "std::get<>" indexes directly? Perhaps you
were only aware of the std::get<>-based version of structured bindings, and
you weren't aware of this, C++17 structured bindings?

That's ok. A reliable solution is still simple. Let's say you wanted, for
whatever reason, for a new std::string to take place of the existing
std::string name that std::get<0> gives you, in this situation.

Of course, the easiest solution is to return the new value as std::get<2>, a
new binding. But let's say you're stubborn and want to add a new one as
std::get<0> and shift the rest. And you want to guarantee a compilation
error?

Well, since you haven't yet written any new code that will use this new
field, you just declare one that's guaranteed to miscompile with any code
that uses the existing std::get<0> in any observable way:

class surname_t {

public:
surname_t(const surname_t &)=delete;
surname_t &operator=(const surname_t &)=delete;
};

Now, define this as your new std::get<0> binding. Compile the end result,
and have your compiler find all the existing usage of std::get<0> for you to
fix. It's going to be a bit difficult to assign it to a std::string. Even
with

auto name=std::get<0>(object);

Whatever subsequent code uses it next will fail. At some point, anything
that expects a std::string here will not find it. Only if this name isn't
used anywhere will let this slip through. But who cares, in that case.

It also seems to me that defining a

template <size_t I> auto get(const UserEntry& u) {
// …
}

is not required. One can simply declare a

template <size_t I> auto get(const UserEntry& u);

and then simply specialize it:

template<> auto get<(size_t)0>(const UserEntry &u)
{
return u.getName();
}

and so on, for the rest.

Now, one can easily respecialize that one as get<1>, leaving get<0>
completely unspecified, and thusly find all existing code that refers to it.
This will guarantee that no references to std::get<0> from existing code
will remain.

Now, you may find some existing code, perhaps something that uses
std::apply, that will now completely fail. But it'll need changing in any
case, to handle the new binding properly, so you can temporarily stub it
out, and put it back when the binding is completed.

And once now the existing code compiles, you've proven that you have no code
that uses the former std::get<0>, as a std::string, or anything else, so now
you're free to bind std::get<0> to an actual, new, std::string, with no
possibility of overlooking some existing reference.

But, even better, you should take this as an opportunity to find every
existing instance of direct usage of std::get<> (since std::get<1> of age,
that was getting an int before, will now be seeing a std::string, and fail),
and replace them with proper structured bindings:

auto &[surname, name, age]=whatever().

I would expect every modern compiler to completely optimize away whichever of
these are not actually used, so they come as cost-free, and future additions
to the structurally-bound class will not require a wrapper class, like this.

> Since you told me I do not know C++ I will leave to you the answer to that
> question, since you obviously know more C++ than me.

Yes, it does seem that I do. I have done precisely things of this nature
safely, and with 0 resulting defects. You just have to understand that these
kinds of breaking API changes should be done in a way that guarantees a
compilation error from any existing code that needs to change, and then have
the compiler find every occurence that needs changing, for you.

It is not difficult to cause a C++ compilation error in existing code. One
of the easiest things to do, in C++.

It is true that you just can't rebind, in this specific example, of
std::get<0> directly to std::string, and rely on the human factor to hunt
down all existing usage of it. You have to force a compilation error, and
have the compiler do it for you. That's what you will need to do, and if it
takes any amount of effort to do it, you make sure that the next time you
have to do it, it won't take much effort at all.

Now, perhaps you can prove that you know more than me here, and think of
some situation where a stub wrapper like this will not cause a compilation
error, but will still have observable changes. But, I'm pretty sure I can
come up with something that will also force a compilation error, in that
case.

> What has been gained by adding this enormous complexity?

The need to avoid declaring a bunch of helper classes, for one. Structured
bindings are not simply about declaring specialization of std::get. It's
much more than that. For example, if one needs to have a function or a
method return two discrete values, no need to declare a new helper class,
just a

std::tuple<int, const char *> so_long()
{
return {42, "And thanks for all the fish"};
}

And then simply get two natural objects from

auto [answer, mostly_harmless] = so_long();

Suddenly, it now becomes much easier for functions to actually return two,
or more, objects, without wearing out one's keyboard.

And by following this model, if so_long() ever needs to return three values,
just do it, and your C++ compiler will find all callers, guaranteed.

> That is my question, that remains. I hope that I answered yours:
>
> YES, THE CODE WILL SILENTLY COMPILE WRONG STUFF.

Sorry. That's still 100% bullshit. It is not difficult to prove that no
existing code will "compile wrong stuff". Not if you actually know C++, and
know how to use it correctly. Now, can you please pay attention, when
someone's teaching you C++?

If you'd like to prove me wrong, give me an example of an existing
structured binding, its existing usage, in some way, and tell me to rebind
the usage to a different one, and I'm confident I'll find a way to change
the binding, temporarily, to make the existing usage ill-formed, and not
compilable.

Nobody ever claimed that rebinding an existing structured binding can be
done in one step, with guaranteed error-free results. Just that there's
always a way to find all existing usage of structured bindings, and force a
compilation error until it's fixed to use the new binding, even a temporary
one, a wrapper of some sorts, that can be quickly dropped after all existing
code is converted.

In my experience, the worst case scenario is where I had to force a
compilation error twice: once in all existing code that used structured
bindings, converting it to temporary scaffolding; and a second time after
the temporary scaffolding gets removed, and the new structured binding gets
put in place.

But there's always a guaranteed way to get a compilation failure, and not
"SILENTLY COMPILE WRONG STUFF" (see, I can use the CAPS LOCK key too).

Jorgen Grahn

unread,
Mar 15, 2020, 7:08:34 AM3/15/20
to
On Sat, 2020-03-14, Öö Tiib wrote:
> On Saturday, 14 March 2020 10:05:58 UTC+2, jacobnavia wrote:
...
>> Why it is so important that you HAVE to add it to an already unbearible
>> complex language?
>
> My guess is that it is perhaps sabotage of wormtongues from monster
> software companies with task to deteriorate the language to non-
> useful. I disliked the language changes in C++17 as well. But I may
> be wrong.

My coworker, who (unlike me) hangs around on HackerNews, understand it
as a kind of pressure. Within a company, people lobby for doing the
next project in $pet_language, because it has $feature which would be
useful. So they grow C++ so it can stay competitive.

Sounds more likely than a conspiracy.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Öö Tiib

unread,
Mar 15, 2020, 12:47:10 PM3/15/20
to
Big part of the language features that C++11 added were vital performance
improvements, others were syntax sugar (often added bordering on
broken) and only very few were security and or safety features.
I remember discussions how safety features like override and final
were planned to be added uglified to maximum.
I can live without using syntax sugar features so did not care that
standards make those broken but safety and performance features I
care about. However C++17 took to break performance feature constexpr
(by making it undetectable) and safety feature enum class (by adding
more undefined behaviors into it). Then I built impression that
it is sabotage.

Bonita Montero

unread,
Mar 15, 2020, 12:50:17 PM3/15/20
to
> What happens when the class is modified to have a new field?

That's not different than with a single type you're
iterating through changes. So where's the problem ?

Alf P. Steinbach

unread,
Mar 15, 2020, 2:27:51 PM3/15/20
to
On 15.03.2020 17:46, Öö Tiib wrote:
> [snap]. However C++17 took to break performance feature constexpr
> (by making it undetectable) and safety feature enum class (by adding
> more undefined behaviors into it). Then I built impression that
> it is sabotage.


Which undefined behaviors for enums?

What I recall is the opposite, that the introduction of `std::bool`
forced a cleanup where now all enumerator values that fit within the
underlying type are kosher also formally.

If they have undermined the language in yet another direction it's,
well, disconcerting.


- Alf

Keith Thompson

unread,
Mar 15, 2020, 6:16:10 PM3/15/20
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
> On 15.03.2020 17:46, Öö Tiib wrote:
>> [snap]. However C++17 took to break performance feature constexpr
>> (by making it undetectable) and safety feature enum class (by adding
>> more undefined behaviors into it). Then I built impression that
>> it is sabotage.
>
> Which undefined behaviors for enums?
>
> What I recall is the opposite, that the introduction of `std::bool`
> forced a cleanup where now all enumerator values that fit within the
> underlying type are kosher also formally.

What is "std::bool"? (Since bool is a keyword, the grammar would have
to be updated just to allow that.)

> If they have undermined the language in yet another direction it's,
> well, disconcerting.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

jacobnavia

unread,
Mar 15, 2020, 7:11:51 PM3/15/20
to
In this code
for (auto const& e : mapCityPopulation) {
char const* city = e.first.c_str();
int population = e.second;
std::cout << city << ": " << population << '\n';
}

Forget for a moment that map has two fields and assume a general class.
When this assignment is written as such, only the fields needed are
accessed.

No assumptions are done about the other fields of the class.


Using structured binding you have to specify the number of fields of the
class and many other IRRELEVANT things that make more dependencies that
make the code more prone to failure.

Instead of accessing just what you need, you end up accessing ALL the
class since you create an anonymous object to which "bindings" are done.

All that unnecessary machinery just to give you

MORE SYNTACTIC SUGAR.

C++ has enough of that. Do you really need to add more? For an end
result that is more complex to write and maintain?

What has been gained with all that machinery?

You have to write your "get" templates that receive the index of the
field, the specification template for the number of fields in the
claass, all that stuff!

Using the more verbose but simpler code if any irrelevant field is
addded to the class you do not access it and your code is inmune to
those changes!

You see the problem now?



Alf P. Steinbach

unread,
Mar 16, 2020, 12:23:25 AM3/16/20
to
On 15.03.2020 23:15, Keith Thompson wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>> On 15.03.2020 17:46, Öö Tiib wrote:
>>> [snap]. However C++17 took to break performance feature constexpr
>>> (by making it undetectable) and safety feature enum class (by adding
>>> more undefined behaviors into it). Then I built impression that
>>> it is sabotage.
>>
>> Which undefined behaviors for enums?
>>
>> What I recall is the opposite, that the introduction of `std::bool`
>> forced a cleanup where now all enumerator values that fit within the
>> underlying type are kosher also formally.
>
> What is "std::bool"? (Since bool is a keyword, the grammar would have
> to be updated just to allow that.)

Sorry, I meant to type `std::byte`.

The perils of having a brain with low level automation of things like
typing up what I was thinking, when higher levels have moved on to other
things. If Odin & his brothers had meant for us to type on QWERTY
keyboards they would have equipped Ask and Embla with seven fingers on
each hand. The time is long overdue for more rational input equipment.

I particularly liked the 80's idea of a little thingy with five buttons
that you pressed in combinations. You could even have it in your wallet
and type unseen. If you were not afraid of the impression it could give.


>> If they have undermined the language in yet another direction it's,
>> well, disconcerting.


- Alf

Bonita Montero

unread,
Mar 16, 2020, 12:24:12 AM3/16/20
to
> Using structured binding you have to specify the number of fields of the
> class and many other IRRELEVANT things that make more dependencies that
> make the code more prone to failure.

People who can handle C++ also can handle this.

Alf P. Steinbach

unread,
Mar 16, 2020, 12:54:46 AM3/16/20
to
Oh dang it happened again. I ordered typing of "pocket", not "wallet".

Öö Tiib

unread,
Mar 16, 2020, 3:20:23 AM3/16/20
to
On Sunday, 15 March 2020 20:27:51 UTC+2, Alf P. Steinbach wrote:
> On 15.03.2020 17:46, Öö Tiib wrote:
> > [snap]. However C++17 took to break performance feature constexpr
> > (by making it undetectable) and safety feature enum class (by adding
> > more undefined behaviors into it). Then I built impression that
> > it is sabotage.
>
>
> Which undefined behaviors for enums?
>
> What I recall is the opposite, that the introduction of `std::bool`
> forced a cleanup where now all enumerator values that fit within the
> underlying type are kosher also formally.

Yes, seems that the resulting broken std::byte of C++17 caused them to
fix enums in C++20.

Sam

unread,
Mar 16, 2020, 6:46:36 AM3/16/20
to
Furthermore, having delicate code that requires substantial work to
implement a tiny change is one of the key defining features of C++, and this
simply makes it even better.


Bonita Montero

unread,
Mar 16, 2020, 7:52:47 AM3/16/20
to
>> People who can handle C++ also can handle this.

> Furthermore, having delicate code that requires substantial work to
> implement a tiny change is one of the key defining features of C++,
> and this simply makes it even better.

The issue here to complain about is the use of auto which results
in intransparent types. I use auto only when absolutely necessary.
In the "auto considered harmful" thread someone give a weird example
which could get seemingly readable by using auto. But I rather prefer
a 40 character type than an auto.

Sam

unread,
Mar 16, 2020, 8:32:18 AM3/16/20
to
So, your argument boils down to mostly personal preference. If you prefer to
explicitly declare every type, you can still do so. This hasn't been
outlawed. You can continue writing out and spelling everything out.

But now, there's an option to simply avoid doing that. And, as an extra
bonus, I can do:

auto e=container.end();

auto p=std::find_if(container.begin(), e, [](const auto &value)
{
return value == 42;
});

if (p != e)
{
std::cout << "Find it" << std::endl;
}

Now, when I suddenly realize that my container must be a std::list, instead
of a std::vector, since there's a new requirement to be able to modify it
without invalidating all existing iterators, you can simply change the
declaration only, and not have to change a shitload of code.

If you prefer to do that, instead, because you believe you gain something
from the pain of doing that, you are welcome to continue writing the same
verbose, explicit declarations you're already doing. But, I'm glad I have
another option, now.

Bonita Montero

unread,
Mar 16, 2020, 8:51:21 AM3/16/20
to
> So, your argument boils down to mostly personal preference.

If you're not the designer of the code or a visionary you've to find
the container-type for which you're getting the auto variable(s). And
that's more work than reading the concrete type.

> Now, when I suddenly realize that my container must be a std::list,
> instead of a std::vector, since there's a new requirement to be able to
> modify it without invalidating all existing iterators, you can simply
> change the declaration only, and not have to change a shitload of code.

Having the concrete type maintains readability - that's more important
than having less typing. As someone said in another thread he got tired
of overly use of auto in a source he didn't write himself.

jacobnavia

unread,
Mar 16, 2020, 11:11:32 AM3/16/20
to
That's the point.

C++ started with many good ideas like "information hiding", in the sense
that you limit the access to irrelevant detail to specify interfaces
that are more robust to changes in the underlying implementation.

Structured binding goes against that principle head on: you expose
everything and any change to the implementation of the base class needs
a rewrite of user code!

The existing way of "binding", i.e. declaring the variables and
assigning to those variables the fields you want to access should be
prefered. Structured binding is a mistake.




Ian Collins

unread,
Mar 16, 2020, 3:17:48 PM3/16/20
to
On 17/03/2020 04:11, jacobnavia wrote:
> Le 16/03/2020 à 11:46, Sam a écrit :
>> Bonita Montero writes:
>>
>>>> Using structured binding you have to specify the number of fields of
>>>> the class and many other IRRELEVANT things that make more
>>>> dependencies that make the code more prone to failure.
>>>
>>> People who can handle C++ also can handle this.
>>
>> Furthermore, having delicate code that requires substantial work to
>> implement a tiny change is one of the key defining features of C++, and
>> this simply makes it even better.
>>
>>
>
> That's the point.
>
> C++ started with many good ideas like "information hiding", in the sense
> that you limit the access to irrelevant detail to specify interfaces
> that are more robust to changes in the underlying implementation.
>
> Structured binding goes against that principle head on: you expose
> everything and any change to the implementation of the base class needs
> a rewrite of user code!

Ah but if you are using a type with named members, you wouldn't need to
use structured binding, would you? Structured binding is useful for
objects with unnamed members (arrays, tuples) or objects with generic
names (map, pair etc).

So no, structured binding is not a mistake.

--
Ian.

Daniel

unread,
Mar 16, 2020, 4:12:45 PM3/16/20
to
On Monday, March 16, 2020 at 11:11:32 AM UTC-4, jacobnavia wrote:
>
> C++ started with many good ideas like "information hiding", in the sense
> that you limit the access to irrelevant detail to specify interfaces
> that are more robust to changes in the underlying implementation.
>
> Structured binding goes against that principle head on:

Not necessarily

> you expose everything and any change to the implementation of the base
> class needs a rewrite of user code!
>

Consider

std::map<std::string, int> m = { {"one",1}, {"two",2} };

for (const auto& [key, value] : m) // (*)
{
std::cout << "key: " << key << ", value: " << value << "\n";
}

for (const auto& kv : m) // (**)
{
std::cout << "key: " << kv.first << ", value: " << kv.second << "\n";
}

(*) reveals less of the implementation detail of std::map than (**),
in particular, it does not depend on the particular representation of the
value_type being std::pair<const std::string,int>.

Daniel

Sam

unread,
Mar 16, 2020, 8:06:24 PM3/16/20
to
Bonita Montero writes:

>> So, your argument boils down to mostly personal preference.
>
> If you're not the designer of the code or a visionary you've to find
> the container-type for which you're getting the auto variable(s). And
> that's more work than reading the concrete type.

I know that if I have a container, I can call begin(), and/or end(), drop
the result into an auto, and have something to work with. I would think this
would save me quite a bit of time for not having to do what you think I
would have to do.

>> Now, when I suddenly realize that my container must be a std::list, instead
>> of a std::vector, since there's a new requirement to be able to modify it
>> without invalidating all existing iterators, you can simply change the
>> declaration only, and not have to change a shitload of code.
>
> Having the concrete type maintains readability - that's more important
> than having less typing. As someone said in another thread he got tired
> of overly use of auto in a source he didn't write himself.

I suppose that it's a matter of personal preference.

I am aware of the fact that iterator and algorithm semantics are remarkably
consistent. People's Exhibit A: my previous message in this thread.

I'm not sure how clearly identifying that something is a list iterator
translates into "readability". If all I need to do is passed something into
std::find, find_if, or some other algorithm that correctly adapts itself to
any compliant iterator, I'm not sure the value added in explicitly
designating the inputs as list or vector iterators. The end result, the
concept, in the end, is the same.

And I find the concept of readability to be quite the opposite of yours'. To
me, a compact designation that something is merely a beginning or an ending
iterator of a sequence is all I need to make it readable. See a spelled out
type take up a quarter of a width of a line, for some reason, doesn't appeal
as very readable to me.

Sam

unread,
Mar 16, 2020, 8:13:44 PM3/16/20
to
jacobnavia writes:

> Le 16/03/2020 à 11:46, Sam a écrit :
>> Bonita Montero writes:
>>
>>>> Using structured binding you have to specify the number of fields of the
>>>> class and many other IRRELEVANT things that make more dependencies that make
>>>> the code more prone to failure.
>>>
>>> People who can handle C++ also can handle this.
>>
>> Furthermore, having delicate code that requires substantial work to
>> implement a tiny change is one of the key defining features of C++, and this
>> simply makes it even better.
>>
>>
>
> That's the point.
>
> C++ started with many good ideas like "information hiding", in the sense
> that you limit the access to irrelevant detail to specify interfaces that
> are more robust to changes in the underlying implementation.
>
> Structured binding goes against that principle head on: you expose
> everything and any change to the implementation of the base class needs a
> rewrite of user code!

So?

Sometimes that's exactly what you want. You may very well want a particular
change to be incompatible, by design, and force all existing callers to
adapt.

And for changes that should not break existing functionality, you have other
ways of skinning that cat. Like adding another enum value, or something. And
all structured bindings that employ that particular enum type continue to
work exactly as they do now. Amazing, isn't it?

And wasn't someone around here just kvetching, recently, how using
structured bindings can end up miscompiling code because it went undetected
and did /not/ require the "rewrite of user code".

Oh, that was you:

# jacobnavia writes:
#
# > As you see the "get" template receives an index that IS HARDCODED TO THE INDEX
# > OF THE FIELD, and any changes by INSERTING A NEW FIELD will make those indexes
# > silently access the WRONG FIELD,

But, you're not saying that /any/ change mandates a rewrite, since it's
going to get miscompiled?

Sir/ma'am/whatever: can you kindly make up your mind exactly what's the
problem with structured bindings?

Bonita Montero

unread,
Mar 17, 2020, 1:37:52 AM3/17/20
to
> I suppose that it's a matter of personal preference.

If I have to figure out of which type a container is I doing an
auto in a for, that's not a matter of preference. If I f.e. have
a pair<const key, value>, I know immediately that I'm using a map
or unordered_map.

Sam

unread,
Mar 17, 2020, 7:18:00 AM3/17/20
to
Well, the trick is to arrange things so that it doesn't matter.

for (auto &[key,value]:container)

will work for that map. But replacing that container with a std::vector of
tuples will also work, if it becomes necessary. You'll be surprised to learn
that the above line of code will remain unchanged.

Something quite similar happened a year or so, ago. I used an unordered_set
of rectangle objects (x/y/width/height) that I used to implement GUI
algorithms. I initially relied on the unordered_set itself to eliminate the
duplicates.

Through profiling I determined a little bit of a bottleneck in set
operations that will benefit from replacing the unordered_set with a vector,
to take advantage of modern CPU's optimizations on linear memory access.

So that's what I did, and I just added a few bits to all the rectangle
container oeprators to dedupe the rectangles after wrangling with them. And,…
that was it. Apart from simply redefining the container as such, and a few
tweaks to a few functions, that was it. 99% of the existing code used auto
and required no changes whatsoever.

So, if someone likes C++ so much that they prefer to do a lot of unnecessary
work, because they think the resulting code is more readable, more power to
them. If they think that

for (std::unordered_set<rectangle>::iterator rb=rs.begin(), re=rs.end();
rb != re; rb++)
{
rectangle &r=*rb;

// …
}

makes their resulting code so beautiful and purty, they can knock themselves
out. As for me,

for (auto &r:rs)

will also work, and I'll just move on to bigger and better things. I think
I'll survive not having to experience the beauty of the resulting code if I
was forced to rewrite it due to the container change.

I think I'll cope with not appreciating the "readability" of knowing that
the underlying iterators are std::unordered_set<rectangle>::iterator or
std::vector<rectangle>::iterator. I'll just have to deal with the fact that
it will never be clear to me how that adds to "readability". For me, it
appears that the exact task at hand, for which I need to chew through the
rectangles, is what's more important. Where those rectangles come from, from
which container, and its semantics, who cares.

Bonita Montero

unread,
Mar 17, 2020, 1:37:46 PM3/17/20
to
> will work for that map. But replacing that container with a std::vector
> of tuples will also work, if it becomes necessary. You'll be surprised
> to learn that the above line of code will remain unchanged.

This ease doesn't justify the lesser readability.

Alf P. Steinbach

unread,
Mar 17, 2020, 1:50:24 PM3/17/20
to
Point.

IMO they could/should just have opened up the $ namespace for keywords.

Instead of all this grotesquely convoluted symbol based syntax.


- Alf

Melzzzzz

unread,
Mar 17, 2020, 3:46:46 PM3/17/20
to
On 2020-03-12, jacobnavia <ja...@jacob.remcomp.fr> wrote:
> Here is one exemple of "structured binding" from the paper of Filipek:
>
> int main() {
> // Initialize a map table.
> const std::map<std::string, int> mapCityPopulation {
> { "Beijing", 21'707'000 },
> { "London", 8'787'892 },
> { "New York", 8'622'698 }
> };
>
> for (auto&[city, population] : mapCityPopulation)
> std::cout << city << ": " << population << '\n';
> }
>
> Within the for statement the variables "city" and "population" will be
> bound automatically to the corresponding fields of the map.
>
> Cute isn't it?
>
> Before, in the old times, you would have to write:
> (I cite the book of Filipek page 29)
>
><quote>
>
> Consider a function that returns two results in a pair:
>
> std::pair<int, bool> InsertElement(int el) { ... }
>
> You can write:
> auto ret = InsertElement(...)
> And then refer to ret.first or ret.second. However, referring to values
> as .first or .second is also not expressive - you can easily confuse the
> names, and it’s hard to read.
><end quote>
>
> Yes, maybe is not "expressive". There is an easy work around though, as
> Filipek shows:
>
><quote>
> Alternatively you can leverage std::tie which will unpack the tuple/pair
> into local variables:
> int index { 0 };
> bool flag { false };
> std::tie(index, flag) = InsertElement(10);
> Such code might be useful when you work with std::set::insert which
> returns std::pair:std::set<int> mySet;
>
> std::set<int>::iterator iter;
> bool inserted { false };
>
> std::tie(iter, inserted) = mySet.insert(10);
> if (inserted)
> std::cout << "Value was inserted\n";
>
> As you see, such a simple pattern - returning several values from a
> function - requires several lines of code.
><end quote>
>
> Yes, several lines of code that is easily read by anyone and by existing
> tools.
>
> And here awe arrive at the essence of why C++ is going into endless
> complexity: a desire to have "cute" constructs and save some seconds to
> the programmer typing the new code in.
>
> Nothing will be said about the need to reprogram all tools that read C++
> code to accept the new stuff, the need to figure out all ramifications
> of the new construct, etc etc.
>
> Because the consequences are terrible when you do not have a 1 to 1
> correspondence between the names in the bracket enclosed list, and the
> class whose fields will be "bound" to those names.
>
>
> Even WORST:
>
> What happens when the class is modified to have a new field?
> All the structured binding constructs have to be modified to add the new
> field, and if you miss one crashes and bugs will inevitably happen.
>
> All of this is not necessary using the old syntax that was more verbose
> but MUCH SAFER and robust.
>
> MINDLESS COMPLXITY FOR COMPLEXITY's SAKE, with no improvement to
> anything useful.
>
> All the tools have to be rewritten to accomodate this nonsense, what is
> not easy since you have to get the definition of the class object that
> can be anywhere else, in another header file or whatever!
>
> What is the end result?
>
> A new useless construct has been added to the language that serves no
> purpose other than saving some seconds when typing C++.
>
> GREAT!

It's called destructuring/pattern match in other languages. C++ wants that badly.
Rust => is that way, and promisses.


--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Sam

unread,
Mar 18, 2020, 6:30:21 AM3/18/20
to
I find it quite the opposite. Verbose code that spells out the data type of
each variable results in too much visual clutter that's taken up by minor
details that are largely irrelevant to the task at hand. When trying to
understand existing code it's more readable to me when the bulk of it
describes what it does, instead of how it does it.

Bonita Montero

unread,
Mar 18, 2020, 6:38:22 AM3/18/20
to
> I find it quite the opposite. Verbose code that spells out the data type
> of each variable results in too much visual clutter that's taken up by
> minor details that are largely irrelevant to the task at hand. ...

The details aren't minor if you aren't the writer of the code or you've
not looked for the code for a long time. I can understand the guy that
told in the auto-thread that he suffered reading code from someone else
who overly used auto.

Sam

unread,
Mar 18, 2020, 8:17:36 AM3/18/20
to
Bonita Montero writes:

>> I find it quite the opposite. Verbose code that spells out the data type of
>> each variable results in too much visual clutter that's taken up by minor
>> details that are largely irrelevant to the task at hand. ...
>
> The details aren't minor if you aren't the writer of the code or you've
> not looked for the code for a long time.

Even if I did not write the code,

for (auto &rectangle:container)
draw(rectangle);

Tells me everything I need to know, without the visual noise of whether
"container" is a set or a vector. That is completely, and utterly
irrelevant. Which will still be completely and utterly irrelevant if I
didn't write that.

> I can understand the guy that
> told in the auto-thread that he suffered reading code from someone else
> who overly used auto.

I can also understand that. After being set in one's ways, and coding in pre-
C++11 for your entire working career, learning something new and different,
and adapting to it, can be tough.

But, it can be done. I was in the same boat about eight years ago. But I
plowed through it, and did it. It took a little bit of time, but it was
doable. Not knowing the type of some object was, at first, a fish-out-of-
water experience, but I figured out at some point how, in many cases, it's
really irrelevant and I don't need to know. Now being exposed to both coding
styles, I like the auto style better. But I can still work with the existing
code base that spells everything out. I can happily work with both styles of
existing code.

And if someone can't, I think that someone will, eventually, just take their
job from them, if it comes down to that. It might even be me.

Bonita Montero

unread,
Mar 18, 2020, 8:19:19 AM3/18/20
to
> Even if I did not write the code,
> for (auto &rectangle:container)
>    draw(rectangle);
> Tells me everything I need to know, without the visual noise of whether
> "container" is a set or a vector.

You need to know it.

> "container" is a set or a vector. That is completely, and utterly
> irrelevant. Which will still be completely and utterly irrelevant if I
> didn't write that.

No, that's relevant if you want to understand the code.

[rest of stupid stuff unread]

Sam

unread,
Mar 18, 2020, 8:31:38 AM3/18/20
to
Bonita Montero writes:

>> Even if I did not write the code,
>> for (auto &rectangle:container)
>>    draw(rectangle);
>> Tells me everything I need to know, without the visual noise of whether
>> "container" is a set or a vector.
>
> You need to know it.

I can decide for myself what I need to know.

>> "container" is a set or a vector. That is completely, and utterly
>> irrelevant. Which will still be completely and utterly irrelevant if I
>> didn't write that.
>
> No, that's relevant if you want to understand the code.

I will concede that some people do need to know that, in order to understand
the code.

But others won't.

Sucks to be the former.

Evolution.

Survival of the fittest.

I learned that in grade school.

> [rest of stupid stuff unread]

Because you have no response to industrial strength, 100%, truth.

That one hit too close to home?

Bonita Montero

unread,
Mar 18, 2020, 9:16:07 AM3/18/20
to
>>> Even if I did not write the code,
>>> for (auto &rectangle:container)
>>>     draw(rectangle);
>>> Tells me everything I need to know, without the visual noise of
>>> whether "container" is a set or a vector.

>> You need to know it.

> I can decide for myself what I need to know.

You can't if you really want to understand the code.

> I will concede that some people do need to know that, in order to
> understand the code.
> But others won't.

If you're involved in the development of the code you need to know it.

> Because you have no response to industrial strength, 100%, truth.

Industrial strength tends to be more readable.
What you suggest is less readable.

Sam

unread,
Mar 18, 2020, 10:13:43 AM3/18/20
to
Bonita Montero writes:

>>>> Even if I did not write the code,
>>>> for (auto &rectangle:container)
>>>>     draw(rectangle);
>>>> Tells me everything I need to know, without the visual noise of whether
>>>> "container" is a set or a vector.
>
>>> You need to know it.
>
>> I can decide for myself what I need to know.
>
> You can't if you really want to understand the code.

That's just your own limitation, but you are assuming that everyone else
shares the same limited capacity to understand code. That is not the case.

>> I will concede that some people do need to know that, in order to understand
>> the code.
>> But others won't.
>
> If you're involved in the development of the code you need to know it.
>
>> Because you have no response to industrial strength, 100%, truth.
>
> Industrial strength tends to be more readable.
> What you suggest is less readable.

It's less readable to you, and you won't understand it. I'm sorry to hear
that. Someone else, who can read the code, will be happy to help you, if
needed.

Bonita Montero

unread,
Mar 18, 2020, 10:45:59 AM3/18/20
to
>> You can't if you really want to understand the code.

> That's just your own limitation, but you are assuming that everyone else
> shares the same limited capacity to understand code. That is not the case.

There's no limitation on my side. It's simply impossible to understand
the code without the underlying container. So you have to find the
definition or declaration of the container, which might be superfluous
work if there would be a concrete type-definition.

> It's less readable to you, ...

No, to everyone.
No one has a crystal ball to gues the type of the container.

Sam

unread,
Mar 18, 2020, 11:36:16 AM3/18/20
to
Bonita Montero writes:

>>> You can't if you really want to understand the code.
>
>> That's just your own limitation, but you are assuming that everyone else
>> shares the same limited capacity to understand code. That is not the case.
>
> There's no limitation on my side.

But you just admitted to one. You freely admit that you can't understand any
code that uses a C++ container until you figure out what the container is.
That's a major limitation of one's ability to understand C++ code.

> It's simply impossible to understand
> the code without the underlying container.

For you, it is. Others don't share that limitation. I can understand it. So
pretty much everyone else.

> So you have to find the
> definition or declaration of the container, which might be superfluous
> work if there would be a concrete type-definition.

No, you don't. You don't need to know what the container is when doing

for (const auto &v:container)
{
if (v == 0)
{
++number_of_zeroes;
}
}

If you don't understand what this does, without looking up what container
is, that's only because you don't know C++ very well.

This is a typical question given to a candidate for a C++ developer job, and
if you can't explain what this does, it is unlikely that you will get the
job. You admit that you have absolutely no clue what this does.

I'm sorry to hear that.

>
>> It's less readable to you, ...
>
> No, to everyone.

No, just you.

> No one has a crystal ball to gues the type of the container.

Noone really needs to know the type of the container, in this instance.

Can I suggest some good C++ books, for you?

Bonita Montero

unread,
Mar 18, 2020, 12:59:44 PM3/18/20
to
>> There's no limitation on my side.
>
> ... That's a major limitation of one's ability to understand C++ code.

Everyone without your crystal ball has this limitation.

> for (const auto &v:container)
> {
>   if (v == 0)
>   {
>      ++number_of_zeroes;
>   }
> }

v can be a type castable to an integer.

> Noone really needs to know the type of the container, in this instance.

But in most other instances.

Sam

unread,
Mar 18, 2020, 1:19:11 PM3/18/20
to
Bonita Montero writes:

>>> There's no limitation on my side.
>>
>> ... That's a major limitation of one's ability to understand C++ code.
>
> Everyone without your crystal ball has this limitation.

Too bad, so sad. I guess you'll have to figure it out without having one,
then. Life's so unfair.

>> for (const auto &v:container)
>> {
>>   if (v == 0)
>>   {
>>      ++number_of_zeroes;
>>   }
>> }
>
> v can be a type castable to an integer.

Or a suitable operator== overload. Please learn a little bit of C++.

>> Noone really needs to know the type of the container, in this instance.
>
> But in most other instances.

In most other instances almost everyone can figure this out too. Just not
you.

Bonita Montero

unread,
Mar 18, 2020, 1:27:52 PM3/18/20
to
>> v can be a type castable to an integer.

> Or a suitable operator== overload. Please learn a little bit of C++.

If you arguing against yourself there's nothing more to say.

> In most other instances almost everyone can figure this out too.
> Just not you.

I do it like everyone, but this is an unecessary effort.

Sam

unread,
Mar 18, 2020, 2:42:03 PM3/18/20
to
Bonita Montero writes:

>>> v can be a type castable to an integer.
>
>> Or a suitable operator== overload. Please learn a little bit of C++.
>
> If you arguing against yourself there's nothing more to say.

Here are your toys. You can go home now.

>> In most other instances almost everyone can figure this out too.
>> Just not you.
>
> I do it like everyone, but this is an unecessary effort.

Not really much of an effort. You just have to know C++.

James Kuyper

unread,
Mar 18, 2020, 2:44:07 PM3/18/20
to
On Wednesday, March 18, 2020 at 12:59:44 PM UTC-4, Bonita Montero wrote:
> >> There's no limitation on my side.
> >
> > ... That's a major limitation of one's ability to understand C++ code.
>
> Everyone without your crystal ball has this limitation.

I don't own a crystal ball. All I have is the ability to understand C++
syntax. Yet that ability is sufficient for me to understand the
following code:

> > for (const auto &v:container)
> > {
> >   if (v == 0)
> >   {
> >      ++number_of_zeroes;
> >   }
> > }
>
> v can be a type castable to an integer.

Yes it can, but that's not a requirement. It would be sufficient for it
to be comparable with 0 for equality. Pointers cannot, in general (there
are specific exceptions) be safely converted to integer types, but they
can all be compared with 0 for equality - the 0 is handled as a null
pointer constant which gets implicitly converted into a null pointer of
the pointer's type before making the comparison. A class type with a
compatible overload for operator==() would also make it work.

If this code has been successfully compiled by a conforming
implementation of C++ without generating any diagnostics, it's
guaranteed that the type is comparable with 0 for equality. If it hasn't
been compiled that way yet, you'll find out the first time you do try to
compile it that way. Of course, if the relevant type is a typedef or a
template parameter, you won't find out until the first time that you
compile it when that typedef or parameter describes a problematic type -
but even so, you will find out at compile time, not run time.

> > Noone really needs to know the type of the container, in this instance.
>
> But in most other instances.

I've found it quite common that I didn't need to know the exact type
that "auto" has been used for. Whenever that is the case, using auto
rather than the explicit type improves the readability. I will agree
that "auto" should not be used when that is not the case.

Bonita Montero

unread,
Mar 18, 2020, 2:47:07 PM3/18/20
to
>> I do it like everyone, but this is an unecessary effort.

> Not really much of an effort. You just have to know C++.

How much depends on the complexity of the type. And if auto is used
regulary in a project the effort sums up to a essential part of the
work.
However, no matter how complex the type is, it's just unecessary.

Bonita Montero

unread,
Mar 18, 2020, 2:48:20 PM3/18/20
to
> I don't own a crystal ball. All I have is the ability to understand
> C++ syntax. Yet that ability is sufficient for me to understand the
> following code:

In this example maybe. But often it's impossible to guess the type.

James Kuyper

unread,
Mar 18, 2020, 3:37:38 PM3/18/20
to
On Wednesday, March 18, 2020 at 2:48:20 PM UTC-4, Bonita Montero wrote:
> > I don't own a crystal ball. All I have is the ability to understand
> > C++ syntax. Yet that ability is sufficient for me to understand the
> > following code:
>
> In this example maybe. But often it's impossible to guess the type.

It's also often unnecessary to guess the type. If it's both necessary
and impossible with this approach, don't use this approach. But there's
nothing wrong with this approach when it's either unnecessary or trivial
to guess the type, and that is often the case.
Keep in mind that it's often not necessary to guess the exact type of
something; it's often only necessary to guess certain characteristics of

Ian Collins

unread,
Mar 18, 2020, 4:05:54 PM3/18/20
to
On 19/03/2020 07:41, Sam wrote:
> Bonita Montero writes:
>
>>>> v can be a type castable to an integer.
>>
>>> Or a suitable operator== overload. Please learn a little bit of C++.
>>
>> If you arguing against yourself there's nothing more to say.
>
> Here are your toys. You can go home now.

See what happens when you feed the troll?

--
Ian.

Sam

unread,
Mar 18, 2020, 7:46:45 PM3/18/20
to
Not only that, but it is not necessary to also use std::vector, std::list,
or any other container in the C++ library. Same thing: none of them are
necessary, and it is possible to do everything they do, by yourself. So,
please stop using them in your code, because it will be quite unreadable, as
a result.

Sam

unread,
Mar 18, 2020, 7:47:15 PM3/18/20
to
I'm still hungry.


Bonita Montero

unread,
Mar 19, 2020, 1:41:44 AM3/19/20
to
> Not only that, but it is not necessary to also use std::vector,
> std::list, or any other container in the C++ library. ...

It doesn't depend on the type of container.
It's usually not possible to guess the contained type.

Sam

unread,
Mar 19, 2020, 7:02:26 AM3/19/20
to
Bonita Montero writes:

>> Not only that, but it is not necessary to also use std::vector, std::list,
>> or any other container in the C++ library. ...
>
> It doesn't depend on the type of container.

Neither does auto.

> It's usually not possible to guess the contained type.

Someone who knows C++ does not need to guess. You're just not very good at
C++. That's ok. C++ is very complicated. Not everyone can manage to learn it
correctly.


Bonita Montero

unread,
Mar 19, 2020, 7:41:55 AM3/19/20
to
>> It's usually not possible to guess the contained type.

> Someone who knows C++ does not need to guess. You're just not very good
> at C++. ...

When you didn't write the code you usually have to check the
type of the container. When you haven't looked at the code for
a long time you might also.

Öö Tiib

unread,
Mar 19, 2020, 9:10:42 AM3/19/20
to
If you know so well C++ then tell us how you conclude the type of
container from following code:

for (std::pair<std::string, int> e : container) {
std::cout << e.first << ": " << e.second << '\n';
}

It works with raw array of pairs, most of standard library
containers and containers from libraries like boost
that allow to have elements of type pair. So if container's
type matters then you have to check it anyway to understand
the code.


Bonita Montero

unread,
Mar 19, 2020, 9:15:47 AM3/19/20
to
> If you know so well C++ then tell us how you conclude the type of
> container from following code:
> for (std::pair<std::string, int> e : container) {
> std::cout << e.first << ": " << e.second << '\n';
> }

You don't need it to know in every caser , but at least you
know the type of its entities; which you don't know with auto.

Daniel

unread,
Mar 19, 2020, 11:24:27 AM3/19/20
to
On Thursday, March 19, 2020 at 7:02:26 AM UTC-4, Sam wrote:
> Bonita Montero writes:
>
> > It's usually not possible to guess the contained type.
>
> Someone who knows C++ does not need to guess.

That's clearly wrong as, depending on the container, type deduction via
auto is not always the right thing to do. One example is std::vector<bool>,
or proxied containers generally.

Daniel

Sam

unread,
Mar 19, 2020, 7:23:20 PM3/19/20
to
But if you know C++, and the code was well-written, even if it was well-
written by someone else you rarely need to do that.

But only as long as you actually know C++.

Bonita Montero

unread,
Mar 20, 2020, 4:19:00 AM3/20/20
to
>> When you didn't write the code you usually have to check the
>> type of the container. When you haven't looked at the code for
>> a long time you might also.

> But if you know C++, and the code was well-written, even if it
> was well-written by someone else you rarely need to do that.


You know it only if you read the part where container was defined
or declared. That's often superfluous if you don't use auto.

James Kuyper

unread,
Mar 20, 2020, 8:31:27 AM3/20/20
to
If know C++, you often don't need to know the exact type, and
therefore don't need to read the part where the container was
defined or declared. That's particularly true if, as specified,
the code was well-written.

Bonita Montero

unread,
Mar 20, 2020, 8:40:21 AM3/20/20
to
> If know C++, you often don't need to know the exact type, and
> therefore don't need to read the part where the container was
> defined or declared. ...

Usually not.

Öö Tiib

unread,
Mar 20, 2020, 11:51:12 AM3/20/20
to
On Friday, 20 March 2020 14:40:21 UTC+2, Bonita Montero wrote:
> On Friday, 20 March 2020 14:31:27 UTC+2, James Kuyper wrote:
>
> > If know C++, you often don't need to know the exact type, and
> > therefore don't need to read the part where the container was
> > defined or declared. That's particularly true if, as specified,
> > the code was well-written.
>
> Usually not.

We have indeed seen that your code is usually not well written,
but ... it is not fault of ours. Try harder?

Daniel

unread,
Mar 20, 2020, 12:31:12 PM3/20/20
to
Nonetheless, Bonita's point, that while usually not necessary to know the
exact type, sometime it is, is valid. Looking only at

for (const auto &v:container)
{

without knowing more about the container, it is not possible to know
by inspection whether type deduction rules via auto will do the right
thing.

Daniel

Bonita Montero

unread,
Mar 20, 2020, 12:41:27 PM3/20/20
to
>>> If know C++, you often don't need to know the exact type, and
>>> therefore don't need to read the part where the container was
>>> defined or declared. That's particularly true if, as specified,
>>> the code was well-written.

>> Usually not.

> We have indeed seen that your code is usually not well written,
> but ... it is not fault of ours. Try harder?

It doesn't depend on how good the code is written. You would have to
have a crystal bulb to guess the type auto refers to in this case.

Öö Tiib

unread,
Mar 20, 2020, 1:13:35 PM3/20/20
to
On Friday, 20 March 2020 18:31:12 UTC+2, Daniel wrote:
> On Friday, March 20, 2020 at 11:51:12 AM UTC-4, Öö Tiib wrote:
> > On Friday, 20 March 2020 14:40:21 UTC+2, Bonita Montero wrote:
> > > On Friday, 20 March 2020 14:31:27 UTC+2, James Kuyper wrote:
> > >
> > > > If know C++, you often don't need to know the exact type, and
> > > > therefore don't need to read the part where the container was
> > > > defined or declared. That's particularly true if, as specified,
> > > > the code was well-written.
> > >
> > > Usually not.
> >
> > We have indeed seen that your code is usually not well written,
> > but ... it is not fault of ours.
>
> Nonetheless, Bonita's point, that while usually not necessary to know the
> exact type, sometime it is, is valid.

It was not the point, the point was that it is *usually* important
to explicitly tell exact type of container and exact type of the
element of it. While more common in bad code is that the container's
and its element's types are very well known since both are stuttered
explicitly both in types and in names of variables all over the place
ad nausea.

> Looking only at
>
> for (const auto &v:container)
> {
>
> without knowing more about the container, it is not possible to know
> by inspection whether type deduction rules via auto will do the right
> thing.

And that is the other property of bad code, things named "iter", "ptr",
"data", "buf", "container" and other such "foo" and "poo".
Like I already wrote here you wont be in any better understanding from:

for (std::pair<std::string, int> e : container) {
std::cout << e.first << ": " << e.second << '\n';
}

To what bonita replied that at least you know that it is
std::pair<std::string, int>. So what? The code is still bad to read.


Jorgen Grahn

unread,
Mar 20, 2020, 1:30:23 PM3/20/20
to
On Fri, 2020-03-20, Daniel wrote:
...
> Nonetheless, Bonita's point, that while usually not necessary to know the
> exact type, sometime it is, is valid. Looking only at
>
> for (const auto &v:container)
> {
>
> without knowing more about the container, it is not possible to know
> by inspection whether type deduction rules via auto will do the right
> thing.

Do you have any examples of containers where that doesn't do the right
thing? (Assuming the loop just wants to visit the elements in
sequence, and not try to modify 'container' or anything.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Daniel

unread,
Mar 20, 2020, 1:36:35 PM3/20/20
to
On Friday, March 20, 2020 at 1:13:35 PM UTC-4, Öö Tiib wrote:
>
> And that is the other property of bad code, things named "iter", "ptr",
> "data", "buf", "container" and other such "foo" and "poo".

I would use "it", for a local iterator variable :-) Also i/j/k for indices.

> Like I already wrote here you wont be in any better understanding from:
>
> for (std::pair<std::string, int> e : container) {
> std::cout << e.first << ": " << e.second << '\n';
> }
>
I disagree. From that, you _know_ that e is not a proxy type.

Daniel

Daniel

unread,
Mar 20, 2020, 1:49:28 PM3/20/20
to
On Friday, March 20, 2020 at 1:30:23 PM UTC-4, Jorgen Grahn wrote:
>
> Do you have any examples of containers where that doesn't do the right
> thing? (Assuming the loop just wants to visit the elements in
> sequence, and not try to modify 'container' or anything.)
>
A trivial example is

#include <vector>
#include <iostream>

void f(bool)
{
std::cout << "bool!\n";
}

template <class T>
void f(T)
{
std::cout << "not bool!\n";
}

int main()
{
std::vector<bool> v = { true,false };

for (const auto& item : v)
{
f(item);
}
}

Output:

not bool!
not bool!

More generally, with proxied containers, all bets are off, think expression
templates or lazy initialization.

Daniel

Jorgen Grahn

unread,
Mar 20, 2020, 2:47:36 PM3/20/20
to
On Fri, 2020-03-20, Daniel wrote:
> On Friday, March 20, 2020 at 1:30:23 PM UTC-4, Jorgen Grahn wrote:
>>
>> Do you have any examples of containers where that doesn't do the right
>> thing? (Assuming the loop just wants to visit the elements in
>> sequence, and not try to modify 'container' or anything.)

...
> std::vector<bool>
...
> More generally, with proxied containers, all bets are off, think expression
> templates or lazy initialization.

Ah, thanks. I don't think I've ever seen any of those in the wild.

Sam

unread,
Mar 20, 2020, 6:05:17 PM3/20/20
to
In your case, definitely. But not in the case of those who have above-
average C++ skills and experience.

Sam

unread,
Mar 20, 2020, 6:06:35 PM3/20/20
to
No, the type it refers to is very obvious.

Daniel

unread,
Mar 20, 2020, 6:58:03 PM3/20/20
to
On Friday, March 20, 2020 at 6:05:17 PM UTC-4, Sam wrote:
>
> In your case, definitely. But not in the case of those who have above-
> average C++ skills and experience.

Bm7 | E7 |
He's Trolling
G F#m7
And he hopes you like trolling too


Ian Collins

unread,
Mar 20, 2020, 7:06:13 PM3/20/20
to
On 21/03/2020 06:36, Daniel wrote:
> On Friday, March 20, 2020 at 1:13:35 PM UTC-4, Öö Tiib wrote:
>>
>> And that is the other property of bad code, things named "iter", "ptr",
>> "data", "buf", "container" and other such "foo" and "poo".
>
> I would use "it", for a local iterator variable :-) Also i/j/k for indices.

One of the first things I encourage my peers to change (and certainly
the first thing I change) when modernising a loop is the iterator
variable name. Using the likes of "it" or "i" may have been natural
before, where the variable was an iterator, but with a ranged for the
variable as a type and should be maned as such. So we have the likes of

for( const auto& line : lines )

rather than

for( std::vector<std::string>::const_iterator it = lines.begin();
it != lines.end(); ++it )

--
Ian.

Öö Tiib

unread,
Mar 20, 2020, 7:37:25 PM3/20/20
to
On Friday, 20 March 2020 19:36:35 UTC+2, Daniel wrote:
> On Friday, March 20, 2020 at 1:13:35 PM UTC-4, Öö Tiib wrote:
> >
> > And that is the other property of bad code, things named "iter", "ptr",
> > "data", "buf", "container" and other such "foo" and "poo".
>
> I would use "it", for a local iterator variable :-) Also i/j/k for indices.

Good idea, "it" instead of "iter" saves whole whopping 2 characters from:

std::vector<std::pair<std::string, int>>::const_iterator it
= container.begin();

> > Like I already wrote here you wont be in any better understanding from:
> >
> > for (std::pair<std::string, int> e : container) {
> > std::cout << e.first << ": " << e.second << '\n';
> > }
> >
> I disagree. From that, you _know_ that e is not a proxy type.

That does not grant me any understanding. I still do _not_ know
if it is copy of object or implicit conversion of it. Ironically
from "auto e" I would at least know that it is copy. Bad code stays
bad.

Daniel

unread,
Mar 20, 2020, 8:17:22 PM3/20/20
to
On Friday, March 20, 2020 at 7:37:25 PM UTC-4, Öö Tiib wrote:
> On Friday, 20 March 2020 19:36:35 UTC+2, Daniel wrote:

> >
> > I would use "it", for a local iterator variable :-) Also i/j/k for indices.
>
> Good idea, "it" instead of "iter" saves whole whopping 2 characters from:
>
> std::vector<std::pair<std::string, int>>::const_iterator it
> = container.begin();
>
Personally, I would use

auto it = container.begin();

(I'm reading a lot of rust code these days, where the convention is to use
very short names.)

> Ironically from "auto e" I would at least know that it is copy.

Yes, but a copy of what? In the case of a proxied container, that would be
a copy of a proxy, which you probably wouldn't want. A proxy cannot be safely assumed to have a life longer than a single statement.

Daniel

James Kuyper

unread,
Mar 20, 2020, 11:15:12 PM3/20/20
to
"Often" is fully compatible with "usually not". A situation that
comes up 30% of the time could still be described as coming up
fairly often, despite not usually coming up. So that doesn't
constitute a disagreement.

Sam

unread,
Mar 20, 2020, 11:23:42 PM3/20/20
to
Daniel writes:

> On Friday, March 20, 2020 at 6:05:17 PM UTC-4, Sam wrote:
> >
> > In your case, definitely. But not in the case of those who have above-
> > average C++ skills and experience.
>
> Bm7 | E7 |

Some kind of a secret code?

> He's Trolling
> G F#m7

I misplaced my secret decoder ring, so this won't work for me.

> And he hopes you like trolling too

Well, all the available evidence suggests that I've been trolling, off and
on, since he/she/it was in diapers. The only major difference is that I only
troll the trollers.


Keith Thompson

unread,
Mar 21, 2020, 12:08:24 AM3/21/20
to
Sam <s...@email-scan.com> writes:
[...]
> Well, all the available evidence suggests that I've been trolling, off
> and on, since he/she/it was in diapers. The only major difference is
> that I only troll the trollers.

No, when you post on a public newsgroup you troll all of us.

If you feed the troll, you are a troll.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Bonita Montero

unread,
Mar 21, 2020, 1:30:50 AM3/21/20
to
>> Usually not.

> In your case, definitely. But not in the case of those who have
> above-average C++ skills and experience.

It doesn't depend on the skills. You have to know the type
of the container which is usually not necessary if there is
an explicit definition of the type iterated through.

Bonita Montero

unread,
Mar 21, 2020, 1:31:29 AM3/21/20
to
>> It doesn't depend on how good the code is written. You would have to
>> have a crystal bulb to guess the type auto refers to in this case.

> No, the type it refers to is very obvious.

... if you know the type of the container.

Ralf Goertz

unread,
Mar 21, 2020, 3:25:07 AM3/21/20
to
Am Fri, 20 Mar 2020 23:23:30 -0400
schrieb Sam <s...@email-scan.com>:

> Daniel writes:
>
> > On Friday, March 20, 2020 at 6:05:17 PM UTC-4, Sam wrote:
> > >
> > > In your case, definitely. But not in the case of those who have
> > > above- average C++ skills and experience.
> >
> > Bm7 | E7 |
>
> Some kind of a secret code?
>
> > He's Trolling
> > G F#m7
>
> I misplaced my secret decoder ring, so this won't work for me.
>
> > And he hopes you like trolling too

The code is not that secret considering that e.g. Bm7 just means
"bd(f#)a" in any order…

jacobnavia

unread,
Mar 21, 2020, 3:32:11 AM3/21/20
to
That is often true, sometimes.

:-)


Daniel

unread,
Mar 21, 2020, 4:36:57 AM3/21/20
to
On Friday, March 20, 2020 at 11:23:42 PM UTC-4, Sam wrote:
> Daniel writes:
>
> >
> > Bm7 | E7 |
>
> Some kind of a secret code?

No, chord suggestions
>
> He's Trolling
> G F#m7
> And he hopes you like trolling too

> I only troll the trollers.

It's not working. Bonita is replying, but staying measured and reasonable.
That's not what a troll wants.

Daniel

Daniel

unread,
Mar 21, 2020, 4:43:28 AM3/21/20
to
On Tuesday, March 17, 2020 at 3:46:46 PM UTC-4, Melzzzzz wrote:
>
> It's called destructuring/pattern match in other languages. C++ wants that
> badly.
> Rust => is that way.
>
Totally agree. If C++17 had gotten matching into the language, there would
have been no need for std::visit <shudder>.

Daniel

David Brown

unread,
Mar 21, 2020, 6:28:08 AM3/21/20
to
Can we pretend that this is stackoverflow.com, mark this post as "the
answer", and close the thread? This pantomime thread has been seriously
tedious.

<https://i.pinimg.com/originals/d5/46/b2/d546b28c3c679602ef229917efff1ed1.gif>

Mr Flibble

unread,
Mar 21, 2020, 9:34:24 AM3/21/20
to
Unsurprisingly tedious, relative speaking, perhaps, of course!

/Flibble

--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin

“You won’t burn in hell. But be nice anyway.” – Ricky Gervais

“I see Atheists are fighting and killing each other again, over who doesn’t believe in any God the most. Oh, no..wait.. that never happens.” – Ricky Gervais

"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."

Sam

unread,
Mar 21, 2020, 9:50:50 AM3/21/20
to
A real C++ developer doesn't need to know the type of a container in order
to implement well-defined algorithms.

You better everyone who writes template code that what they're doing is
impossible. They're writing code that operates on templates whose type they
don't know, after all.

Sam

unread,
Mar 21, 2020, 9:51:38 AM3/21/20
to
Bonita Montero writes:

>>> Usually not.
>
>> In your case, definitely. But not in the case of those who have above-
>> average C++ skills and experience.
>
> It doesn't depend on the skills.

Yes, it does.

> You have to know the type

If you have the right skills, you don't need to know the type. That's what
separates a real C++ developer from a wanna-be.


Bonita Montero

unread,
Mar 21, 2020, 10:00:06 AM3/21/20
to
> You better everyone who writes template code that what they're doing is
> impossible. They're writing code that operates on templates whose type
> they don't know, after all.

Usually the container isn't a template-parameter itself so you know

Daniel

unread,
Mar 21, 2020, 10:12:09 AM3/21/20
to
On Saturday, March 21, 2020 at 6:28:08 AM UTC-4, David Brown wrote:

Regarding auto, the only substantive issue here is whether auto can always be
used safely, and the _answer_ is clearly and demonstrably "no", which is
Bonita's point. In particular it can't be used with classes following popular
proxy idioms without introducing undefined behavior.

I don't believe that's applicable to the OP's post, though :-)

Daniel

Sam

unread,
Mar 21, 2020, 10:42:55 AM3/21/20
to
Completely wrong, you're just not very experienced with template
metaprogramming.

Sam

unread,
Mar 21, 2020, 10:45:35 AM3/21/20
to
Daniel writes:

> On Saturday, March 21, 2020 at 6:28:08 AM UTC-4, David Brown wrote:
>
> Regarding auto, the only substantive issue here is whether auto can always be
> used safely, and the _answer_ is clearly and demonstrably "no", which is
> Bonita's point.

Can a while loop always be used safely? Of course not. I've seen plenty of
while-loops that result in undefined behavior, due to memory corruption.

Everyone: please stop using while loops. They are not safe.

Daniel

unread,
Mar 21, 2020, 11:03:20 AM3/21/20
to
On Saturday, March 21, 2020 at 10:45:35 AM UTC-4, Sam wrote:
>
> Can a while loop always be used safely? Of course not.

"Therefore, send not to know
For whom the troll trolls,
It trolls for thee."

Bonita Montero

unread,
Mar 21, 2020, 11:09:14 AM3/21/20
to
>> Usually the container isn't a template-parameter itself so you know
>> the type of the container.

> Completely wrong, you're just not very experienced with template
> metaprogramming.

You didn't understand what I wrote.

Sam

unread,
Mar 21, 2020, 11:12:32 AM3/21/20
to
Only the voices in your head understand what you write.

Öö Tiib

unread,
Mar 21, 2020, 1:09:21 PM3/21/20
to
On Saturday, 21 March 2020 02:17:22 UTC+2, Daniel wrote:
> On Friday, March 20, 2020 at 7:37:25 PM UTC-4, Öö Tiib wrote:
> > On Friday, 20 March 2020 19:36:35 UTC+2, Daniel wrote:
>
> > >
> > > I would use "it", for a local iterator variable :-) Also i/j/k for indices.
> >
> > Good idea, "it" instead of "iter" saves whole whopping 2 characters from:
> >
> > std::vector<std::pair<std::string, int>>::const_iterator it
> > = container.begin();
> >
> Personally, I would use
>
> auto it = container.begin();

And I don't use neither "it" nor "container" for name of anything.

> (I'm reading a lot of rust code these days, where the convention is to use
> very short names.)

Perhaps people are translating their legacy algorithms from FORTRAN to see
how it performs.

> > Ironically from "auto e" I would at least know that it is copy.
>
> Yes, but a copy of what? In the case of a proxied container, that would be
> a copy of a proxy, which you probably wouldn't want. A proxy cannot be safely assumed to have a life longer than a single statement.

I do not have nor use peroxided containers. Several tools warn me about
std::vector<bool> usage. It is not container nor does it contain bools.
Such things are worse than raw pointers that at least lack bloat.
You use it? Maybe you overload operator,() and unary operator&() as
well ... I don't and my tools warn about lot of such usage of nuisance
language features that should not be there at first place.


It is loading more messages.
0 new messages