Thursday, August 11, 2022

Digest for comp.lang.c++@googlegroups.com - 24 updates in 7 topics

Juha Nieminen <nospam@thanks.invalid>: Aug 11 06:24AM

> The more pertinent question is why the C++ committee felt the need to
> duplicate the functionality of typedef.
 
typedef is confusing. The average person learning C or C++ very easily
gets the impression that typedef works like:
 
typedef TheType AliasName;
 
But that's not at all how it works. It just happens to conform to that
form with elementary types (because that's how elementary type variables
are declared), but when such a person finds the need to create a type
alias eg. for a function pointer (or any of the other more complicated
types, like array pointers), he'll be highly confused because the
above pattern doesn't work with them. A bit of research needs to be
done to find out that eg. a function pointer alias needs to be written
in a quite confusing way:
 
typedef int(*AliasName)(int, int, double);
 
(Understanding typedef becomes easier when you realize that it's just
as if you were declaring a normal variable, and you just add 'typedef'
at the beginning. But given how obscure function and array pointers are...)
 
The new alternative is more logical, consistent and easier to understand:
 
using AliasName = TheType;
 
In this case it *does* always work using that pattern.
 
> On a large C++ unix project that only uses typedefs for defining types:
 
> grep typedef $(find -E . -regex ".*\.(h|hpp|cc|cpp)")
 
In any shell supporting globbing you can just write
 
grep typedef **/*.(h|hpp|cc|cpp)
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 11 04:37PM +0100


> typedef is confusing. The average person learning C or C++ very easily
> gets the impression that typedef works like:
 
> typedef TheType AliasName;
 
I suppose that depends on what they've read and seen.
 
> as if you were declaring a normal variable, and you just add 'typedef'
> at the beginning. But given how obscure function and array pointers
> are...)
 
I think it's easier for old hands who learned from the classic K&R. K&R
was always very clear: typedef came late to C, and was added into the
syntax as a storage class specifier, just to get the job done. Once you
know this, it's clear that typedef, like extern and static, just sits at
the front of a set of otherwise ordinary declarations.
 
> The new alternative is more logical, consistent and easier to understand:
 
> using AliasName = TheType;
 
> In this case it *does* always work using that pattern.
 
Well that's an odd way to put it. You gave the wrong pattern so of
course this new syntax looks more consistent. typedef (like any
syntax!) also works using a consistent pattern.
 
--
Ben.
Juha Nieminen <nospam@thanks.invalid>: Aug 11 08:12PM

> Well that's an odd way to put it. You gave the wrong pattern so of
> course this new syntax looks more consistent. typedef (like any
> syntax!) also works using a consistent pattern.
 
Yeah, using C's crazy type declaration syntax, which only a fraction
C (or C++) programmers fully understand and remember by heart.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 12 12:09AM +0100

>> syntax!) also works using a consistent pattern.
 
> Yeah, using C's crazy type declaration syntax, which only a fraction
> C (or C++) programmers fully understand and remember by heart.
 
I don't think there are that many people will write
 
using fp = int (*)(int, double);
 
but just baulk at
 
typedef int (*fp)(int, double);
 
What C calls a "type name" -- the int (*)(int, double) part -- is the
bit that bothers most people, at least in my limited experience.
 
But you probably have much wider experience of what modern C programmers
know and don't know.
 
--
Ben.
Juha Nieminen <nospam@thanks.invalid>: Aug 11 08:17AM

I have noticed quite many times a rather curious phenomenon when it
comes to using the 'std::' prefix and the type aliases in <cstdint>:
 
There's a lot of C++ programmers who will use the 'std::' prefix
for all standard library names (including those that come from the
C standard library)... except for the type aliases in <cstdint>,
such as int32_t, uint64_t, size_t, etc. They do this extremely
consistently: The prefix with every other standard library name,
never with the standard library integer type aliases.
 
This phenomenon seems to be strangely common. I wonder why.
 
(AFAIK the standard does not guarantee that the unprefixed names
will work unless you #include <stdint.h>. They never do that,
however. And even those who do... well, I still can't really
comprehend why they meticulously use the prefix with everything
except those type aliases.)
Gawr Gura <gawrgura@mail.hololive.com>: Aug 11 02:19AM -0700

On 8/11/22 01:17, Juha Nieminen wrote:
> however. And even those who do... well, I still can't really
> comprehend why they meticulously use the prefix with everything
> except those type aliases.)
 
What's to wonder about? People write software based on their
understanding of conventions and not a pedantic commitment to the
wording of the standard. Apparently, unlike various other names found in
the standard library, the standard integer types don't present enough
surprises when used in this way for people to change what they're doing.
 
Personally, I always use the qualified name (e.g., std::int32_t) or an
alias. I'm partial to defining i8, i16, i32, i64, and so on. What's your
preference?
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 11 04:28PM +0100

> consistently: The prefix with every other standard library name,
> never with the standard library integer type aliases.
 
> This phenomenon seems to be strangely common. I wonder why.
 
Maybe they think of these types (or maybe they may want to suggest that
these types) are more like the standard types int, long an so on?
 
Maybe they are not sure that the C standard does not give permission for
these names to be macros? (It doesn't.)
 
--
Ben.
Juha Nieminen <nospam@thanks.invalid>: Aug 11 08:14PM

> Maybe they think of these types (or maybe they may want to suggest that
> these types) are more like the standard types int, long an so on?
 
I myself got bitten by that... but in reverse.
 
After all, wchar_t looks exactly like those other type aliases.
Yet it's not.
Andreas Kempe <kempe@lysator.liu.se>: Aug 11 05:38PM

> - Batteries-included approach: compiler, libraries, docs, tools,
> package manager, and more
 
> Apparently those are things believed to be missing for C++.
 
The batteries-included part seems like something that is very much
today's flavour. You want a compiler that enforces a project
structure, handles fetching dependencies for you (Go can include
Github repositories directly in source if I'm not mistaken), lints
your code, generates documentation etc.
 
To some extent, it feels like these new programming languages are more
of an ecosystem that you need to buy into and do everything their way
rather than being a compiler and a grammar turning your scribbles into
machine code.
 
An example to compare with C++ is the problem of choosing your build
system. Do you use Scons, CMake, Automake, GNU Make, BSD Make, etc?
Freedom is nice, but I can understand why someone wouldn't want to put
energy into choosing a build system.
 
I don't really know how to feel about this. Maybe providing one true
way of organising your build system, managing dependencies etc.
dictated by the language is the way of the future?
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Aug 11 12:06PM -0700

On 8/11/2022 10:38 AM, Andreas Kempe wrote:
> structure, handles fetching dependencies for you (Go can include
> Github repositories directly in source if I'm not mistaken), lints
> your code, generates documentation etc.
 
Fwiw, check this out:
 
https://vcpkg.io/en/index.html
 
;^)
 
[...]
Paavo Helde <eesnimi@osa.pri.ee>: Aug 11 11:09PM +0300

11.08.2022 20:38 Andreas Kempe kirjutas:
 
> I don't really know how to feel about this. Maybe providing one true
> way of organising your build system, managing dependencies etc.
> dictated by the language is the way of the future?
 
There is an xkcd about this: https://xkcd.com/927
Quintus Francis Cerimon Fitzwalter <crypticnenad@gmail.com>: Aug 11 09:04AM -0700

I think that this programming language is very useful and many things are written in C++ not. For example I want to build my own ecommerce website and it will be in C++ for sure.
Sabina Babington <lourdesperdon777@gmail.com>: Aug 11 10:19AM -0700

C++ for online store? I think it was good in the past, maybe, but in 2022 most of the successful ecommerce projects work on Python. Anyway, you can double check with https://intexsoft.com/ as they are the leading agency in web development for enterprises and both small and big businesses. I feel even curious what they will recommend in the end of the day.
Manfred <noname@add.invalid>: Aug 11 04:25AM +0200

On 8/10/2022 10:13 AM, David Brown wrote:
 
> That wording implies that it was once a more acceptable term - I don't
> think anyone knowledgable in the two languages has been happy about
> conflating them.  (It's fine to say "C /and/ C++", or "C /or/ C++".)
 
I first heard of C++ in the late '80s, and it was described to me as:
"It's C, wherein structs can contain functions" (which sounded
immediately as a cool feature to me).
At that time C/C++ was not a Bad Word™, and I think this was justified,
for 2 main reasons:
- C++ was still relatively young, and the view of C++ as a mere
evolution of C was still diffuse. It would take some more time for C++
programmers to gain more maturity and fully grasp the different
landscape of the two (see how many are still arguing that C code is C++
code as well, even today)
- C++11 had not happened, yet.
 
Today, none of the above is true.
 
> casting the result of calls to malloc - the casts are perfectly fine in
> C, but not idoimatic) and without a change in functionality.  C is the
> base language on which C++ builds.
 
I disagree. If you program in C++, i.e. you model a problem domain in
C++ from scratch, then you end up with a /very/ different result than
you would if you used C.
 
> reason.  Indeed, a good deal of the things people dislike about C++, or
> that are not "good modern language design", trace back to compatibility
> with C.
 
What I mean by "mixed" here is in fact "confused". Nothing to do with
C++ calling C functions, and vice versa (however this might be accomplished)
 
> that is compiled as both C and C++ is the C headers, but you sometimes
> get more complicated headers that provide different features depending
> on the language at the time.
 
Well, I think you agree that a C++ application using a C library is not
really about mixing the two languages, don't you?
 
>> in fact writing C code, not C++.
 
> That's just silly.  You are, in fact, writing code that is C code /and/
> C++ code.  It might not be idiomatic code, but it is perfectly valid.
 
Again, I disagree. And it is not silly.
 
Let's take an example that makes some sense: you write some code that
involves a linked list (or any other container, for that matter) -
consider a C implementation and a C++ implementation.
 
Are you seriously arguing that the C implementation is a C++
implementation just as well?
(Please note that I /know/ that the C implementation would be legal C++
code. I'm just saying that if you write such a C implementation in a C++
program, then you are Doing It Wrong™)
 
Manfred <noname@add.invalid>: Aug 11 04:29AM +0200

On 8/10/2022 9:50 PM, Scott Lurndal wrote:
 
> Or you might be writing code to solve a problem and realize that
> calling it C, C++, C/C++ or fred doesn't matter so long as the
> program solves the problem.
 
Or you might use Java, Python, Perl, ADA, Fortran, COBOL, ECMAScript -
and solve the same problem.
Does it mean they are all the same language?
Juha Nieminen <nospam@thanks.invalid>: Aug 11 07:04AM

> Note that the expression (C/C++) is considered a Bad Word nowadays.
 
I think pointing that out is quite nitpicky.
 
I believe the vast majority of people are using "C/C++" in a similar
manner as they would use eg. "and/or".
 
In other words, "C/C++" is simply shorthand for "C or C++ (inclusive)".
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Aug 11 01:03AM -0700

On Thursday, 11 August 2022 at 03:26:05 UTC+1, Manfred wrote:
> I disagree. If you program in C++, i.e. you model a problem domain in
> C++ from scratch, then you end up with a /very/ different result than
> you would if you used C.
 
It depends what sort of programming you are doing. I work with algorithms.
For example the other day I was looking at nesting (the problem of packing
small objects into bins). There are several ways of approaching the problem,
none of which bear any relation to the programming language you happen
to be using.
> (Please note that I /know/ that the C implementation would be legal C++
> code. I'm just saying that if you write such a C implementation in a C++
> program, then you are Doing It Wrong™)
 
I've got several bits of code where you need two linked lists. The objects
are placed round the perimeter of closed shapes, so they have "previous"
and "next" members. However they are also in another ordering. For
instance if the shapes intersect and the goal is to create another shape
by joining intersections.
Often you need to split or delete the objects as part of processing.
 
The way I implement this is to just use the C method. I have "previncontour",
"nextincontour" and "previnresult", "nextinresult" pointer members.
It's maybe not the best way of doing it, but it is simple and it works.
However the code is C++, the objects are C++ classes rather than C
structs.
Juha Nieminen <nospam@thanks.invalid>: Aug 11 08:11AM


> I disagree. If you program in C++, i.e. you model a problem domain in
> C++ from scratch, then you end up with a /very/ different result than
> you would if you used C.
 
Sometimes that's a good thing, sometimes not so much.
 
There's a portion of C++ programmers (thankfully a relatively small
portion in my experience) who think that anything that comes from C
should be avoided if there's a C++ equivalent. Combine that with a
lack of "know your tools" experience and it often results in code
that's more inefficient and wasteful than it would need to be.
 
My answer to that kind of mentality is always along the lines of,
for example, "std::fopen() *is* C++. If it's standard C++, then it's
C++. How can you even say that something supported by the C++ standard
is 'not C++'? Know your tools. If it's the best tool for a particular
task, then use it. It doesn't matter if it 'comes from C'. Who cares?
There are tons of things in C++ that 'come from C'. Would you avoid
using 'for' loops because they 'come from C'?"
David Brown <david.brown@hesbynett.no>: Aug 11 01:53PM +0200

On 11/08/2022 04:25, Manfred wrote:
> code as well, even today)
> - C++11 had not happened, yet.
 
> Today, none of the above is true.
 
Yes, C++ was originally "C with classes", and it is not unreasonable to
have used the term "C/C++" in those early days. I was thinking from the
time when C++ became more established and standardised as a language of
choice for a lot of types of development. But I take your point.
 
 
> I disagree. If you program in C++, i.e. you model a problem domain in
> C++ from scratch, then you end up with a /very/ different result than
> you would if you used C.
 
C++ is multi-paradigm. There is no single "C++ way" to model a task or
program. It can be done in lots of different ways, depending on the
task and the people working on it. The same applies to a fair extent to
C - I have seen plenty of C programs that are object oriented in design,
or event based, or have "actors" passing messages between them, or many
other ways to organise the C code. It may be true that much of C
programming is "plain imperative" - sets of functions that do things.
But it is not restricted to that.
 
Now, C++ certainly makes many other types of code structure and task
modelling easier - more natural in the language, more efficient to
write, more efficient at run-time, and better static checking. So when
deciding how to attack a programming task, you might pick different
approaches with C++ than with C, because of different balances in what
fits well with the language. But equally you might not do so - if the
problem lends itself to an imperative approach, you can do that in C++
too (and take advantage of better typing and other features that C does
not have).
 
 
 
> What I mean by "mixed" here is in fact "confused". Nothing to do with
> C++ calling C functions, and vice versa (however this might be
> accomplished)
 
Well, in that sense the languages most certainly /can/ be "mixed" - it
is done regularly. What you mean, I think, is that they should not be
mixed - you feel a programmer should either think, model and design in a
"C way" and program in C, or they should think, model and design in a
"C++ way" and program in C++.
 
While I think there is something in that argument, I don't see it as
clear-cut or absolute.
 
>> on the language at the time.
 
> Well, I think you agree that a C++ application using a C library is not
> really about mixing the two languages, don't you?
 
In embedded systems like this, everything is compiled together. Even if
you don't touch the library source code itself, it's common to have
hooks, user-defined macros, callbacks, and other connections so that the
library code can absolutely be using the programmer's own code. Plenty
of mixing goes on.
 
> (Please note that I /know/ that the C implementation would be legal C++
> code. I'm just saying that if you write such a C implementation in a C++
> program, then you are Doing It Wrong™)
 
I appreciate what you are saying - I just think it is blatantly
incorrect to say the code is "C, not C++". What you mean is that it is
not /idiomatic/ C++ code. It is not code written in a way that /you/
would write it in C++.
 
C++ is used in a huge range of systems, with a huge range of different
requirements. You think that if someone needed a dynamically resizeable
list of items, in C++ they'd always reach for a std::vector while in C
they'd write it themselves, and therefore the languages are different.
When I program in C++, if I needed such a list I'd write it myself, far
closer to what you think of as "C style". The standard library
std::vector will not do what I need it to do, so I would not use it.
But what I write would still be C++.
Andreas Kempe <kempe@lysator.liu.se>: Aug 10 11:41PM

> }
> yields: "warning: 'a' is used uninitialized" when a in fact is
> initialized to 0 implicitly, is it not?
 
I'm a little late on the ball, but as has been stated, stack variables
are not automatically initialised on declaration. To initialise the
variable, you can either write
 
int a = 0;
 
or, in modern C++, you can also write
 
int a{};
 
Let me provide a little test program that should probably show this
being the case.
 
test.cpp:
 
#include <iostream>
 
void a()
{
int a = 5;
}
 
int b()
{
int b;
b += 2;
 
return b;
}
 
int main()
{
a();
 
std::cout << b() << std::endl;
}
 
When this program is compiled on my machine using clang without
optimisation:
 
clang++ -O0 test.cpp -o test
 
It outputs the number 7 because of the two ints ending up on the same
place in the stack.
 
/tmp> ./test
7
 
It might produce something else on your machine. Writing "int b{};" or
"int b = 0;" makes it produce the correct output of 2.
 
I've had cases where I'm passing structs to system calls where I've
forgotten the curly-braces after the declaration, leading to some
unexpected results when some fields get random data. This case not
being caught by the compiler since I do set some fields.
Richard Damon <Richard@Damon-Family.org>: Aug 10 09:30PM -0400

On 8/10/22 7:41 PM, Andreas Kempe wrote:
 
> int a = 0;
 
> or, in modern C++, you can also write
 
> int a{};
 
Actually, ALL variables are "initialize" on declaration. If the object
is a class, then its constructor is run.
 
The problem is with the built-in types, the implicit constructor doesn't
set its value to anything (but file scope or static variables are
automatically defaut initialized). This is different that class objects,
where the "implicit" constructor is the "default" constructor.
 
Giving an explicit value of an explict call to the default constructor
gets you the defined value.
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Aug 11 11:11AM +0200

On 11 Aug 2022 03:30, Richard Damon wrote:
> set its value to anything (but file scope or static variables are
> automatically defaut initialized). This is different that class objects,
> where the "implicit" constructor is the "default" constructor.
 
Uhm, since that's all about terminology I'd better correct it.
 
Default initialization for a basic type does nothing whatsoever, so
that's not the other-than-nothing that happens for static variables.
 
Namespace scope variables are automatically /zero-initialized/. That's
the first of three distinct phases of initialization. The following are
PHASES, the three phases are 1.1, 1.2 and 2:
 
1. /Static initialization/ is performed for variables with static or
thread storage duration, and consists of
1.1 /Zero-initialization/ zeroes variables. Formally it's not
performed for a variable that instead is constant-initialized.
1.2 /Constant initialization/ is where a variable is initialized
with a compile time constant initializer.
2. /Dynamic initialization/ is all other initialization, and happens
after static initialization. The standard differentiates between
unordered, partially ordered and ordered dynamic initialization.
Partially ordered is in C++17 for "an inline variable that is not an
implicitly or explicitly instantiated specialization".
 
In practice the values of static initialization for static storage
duration can just be part of the executable's image loaded into memory
to run the program.
 
Anyway, what you intended to write was probably "but static and thread
storage variables are automatically zero-initialized".
 
Another point: whether one imagines a do-nothing constructor, or that
simply nothing happens, is a point of view. Both views are valid, they
cannot be distinguished by effects. At least I believe so. :-o
 
 
> Giving an explicit value of an explict call to the default constructor
> gets you the defined value.
 
Not sure what that is intended to communicate.
 
 
- Alf
Andreas Kempe <kempe@lysator.liu.se>: Aug 11 11:38AM


> Another point: whether one imagines a do-nothing constructor, or that
> simply nothing happens, is a point of view. Both views are valid, they
> cannot be distinguished by effects. At least I believe so. :-o
 
I've never really considered the fundamental types as having
constructors since they don't have other class/struct semantics, ex.
I can't inherit them. I agree with you that I don't think the
viewpoint matters for the end result.
 
This discussion made me realise something I hadn't realised before,
which is that I can create a simple class with a deleted default
constructor and still zero-initialise it
 
class num
{
public:
num() = delete;
int a;
};
 
int main()
{
//num my_num; // Not allowed because deleted default constructor.
num my_num{}; // Okay, initialises num::a to zero
 
std::cout << my_num.a << std::endl;
}
 
I relised this when looking at value-initialisation and coming across
 
9.1.2 if T has either no default constructor
([class.default.ctor]) or a default constructor that is
user-provided or deleted, then the object is default-initialized;
 
I learnt something new today, thank you.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Aug 10 11:12PM -0700

On 8/4/2022 11:46 PM, Chris M. Thomasson wrote:
> points plotted. So, I need to create a new canvas that has a nice cache
> aligned setup. Have some ideas. This deserves a new thread. Will be all
> in C++.
 
Ahhh.... The quick and easy way. I create N worker threads, each with
its own copy of the vector field, and its own file to plot to. This
eliminates any worker threads possibly fighting over the same pixel.
After the main workload is completed by the worker threads, The main
thread assembles the final rendering by superimposing the workers render
results. Should work.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: