Thursday, January 31, 2019

Digest for comp.lang.c++@googlegroups.com - 21 updates in 3 topics

Bart <bc@freeuk.com>: Jan 30 11:37PM

On 30/01/2019 22:18, Melzzzzz wrote:
 
>> void f(){g("two"); g(&f);}
>> void g(float x){};
 
> No. You don't have type check. I meant no need for prototypes.
 
Which you get with out of order declarations. I solved this long ago in
my own languages, and wouldn't be able to do without the feature now.
 
However, while it was easy to solve within one module (it just needs an
extra pass compared with C or C++), dealing with mutually imported
modules is another matter.
 
>> has modules:
> This problem is solved in other languages. You either parse all library
> files as single file, or ....
 
My approach [in my language] works when all source files comprising the
program unit (single executable or library file) are compiled at the
same time, sharing a global symbol table (the output is the executable).
 
Parsing is performed across all modules before proceeding to the next
stage, which is resolving names. And that process can now cross between
modules because everything is in memory.
 
(For external libraries it still relies on manually created files of
declarations, necessary anyway as most will be in a different language.)
 
There are still a number of problems, one of which is this: with a
purely hierarchical import structure, it is easy to construct a
load-order for the modules. That means that when modules contain
initialisation routines, all those can automatically be called in the
right order.
 
But with circular imports, that load-order is not determinable. If A
imports B, and B imports A, whose initialisation routine do you call
first? Each may require the other to have been set up already. You have
to sort it out manually.
 
--
bart
Melzzzzz <Melzzzzz@zzzzz.com>: Jan 30 10:19PM

> "make" (or ninja, or whatever) will handle it fine. If you have enough
> modules for the build speed and parallel compilation to matter, there
> will be plenty of opportunity for parallelising.
 
No problems with make. Compilers must accomodate.
 
--
press any key to continue or any other to quit...
Paavo Helde <myfirstname@osa.pri.ee>: Jan 31 08:14AM +0200

On 31.01.2019 1:37, Bart wrote:
> my own languages, and wouldn't be able to do without the feature now.
 
> However, while it was easy to solve within one module (it just needs an
> extra pass compared with C or C++)
 
C++ is perfectly capable of doing the needed extra pass by itself, it
just needs a little syntax sugar:
 
struct mynamespace {
 
static void f(double x) { g(x-1); }
 
static void g(float x) { if (x>0) { f(x); }}
 
};
 
int main() {
mynamespace::f(100);
}
David Brown <david.brown@hesbynett.no>: Jan 31 08:23AM +0100

On 31/01/2019 00:37, Bart wrote:
 
>> No. You don't have type check. I meant no need for prototypes.
 
> Which you get with out of order declarations. I solved this long ago in
> my own languages, and wouldn't be able to do without the feature now.
 
C, C++ and many other languages support declarations (or "prototypes",
or "forward declarations" - the terminology varies by language) before
definitions. That solves any circular dependency issues within a module
quite happily. Co-recursive functions are a rarity in code.
 
Some people like to organise their files "backwards" - they like to
define a function first, then further down in the file they define the
functions that it calls. That is fine, but will mean you need more
separate prototype declarations in C. For people who like that code
arrangement, C's methods are a little inconvenient. (As Paavo points
out, C++ no longer needs that if you feel it is an issue.)
 
 
> However, while it was easy to solve within one module (it just needs an
> extra pass compared with C or C++), dealing with mutually imported
> modules is another matter.
 
Ordering is not a problem in the slightest for modules. Mutually
dependent imports (circular imports) are an issue, but these can almost
always be avoided in your code structuring.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jan 31 06:47AM -0500

On 1/31/19 02:23, David Brown wrote:
...
> C, C++ and many other languages support declarations (or "prototypes",
> or "forward declarations" - the terminology varies by language) before
> definitions.
 
While the terminology does vary by language, neither C nor C++ use the
term "prototype" to make such a distinction. Do you know of some other
language where it is used for that purpose? In C and C++, a prototype
can occur in either a forward declaration or in the declaration that
appears at the start of a function definition. In C, a forward
declaration need not be a prototype, and the same is true of the
declaration which appears a the start of a function definition. "forward
declaration" and "defining declaration" is a distinction that's
completely independent of the distinction between "prototyped
declaration" and "non-prototyped declaration" (with the latter appearing
only in C).
Bart <bc@freeuk.com>: Jan 31 12:06PM

On 31/01/2019 07:23, David Brown wrote:
> or "forward declarations" - the terminology varies by language) before
> definitions.  That solves any circular dependency issues within a module
> quite happily.
 
That doesn't solve it at all. Actually it is /part/ of the problem we're
trying to solve! And sometimes you can't neatly get around it:
 
enum {a,b,c=y,d};
enum {w=b,x,t,z};
 
You can't reorder these. And you can't split them up if a,b,c,d and
w,x,y,z belong together, and you still want to rely on auto-increment.
But it's easy to see that a,b,c,d should be 0,1,3,4 and w,x,y,z is
1,2,3,4 (see sig).
 
Any 'solutions' will spoil the code.
 
> Co-recursive functions are a rarity in code.
 
Co-recursion has some technical meaning which I'm not sure is the one
that is relevant here. If you mean that A() calls B() which calls A(),
then I write such code all the time.
 
> separate prototype declarations in C.  For people who like that code
> arrangement, C's methods are a little inconvenient.  (As Paavo points
> out, C++ no longer needs that if you feel it is an issue.)
 
With an extra construct? Having this natively possible anywhere in a
language, without having to worry about such things at all, is more
desirable:
 
E readexpr(void) { ... return readterm();}
E readterm(void) { ... return readexpr();}
 
 
> Mutually
> dependent imports (circular imports) are an issue, but these can almost
> always be avoided in your code structuring.
 
I've had experience of this and often found it difficult to impossible.
99% of functions would fit into the hierarchy, but there were always odd
ones that didn't.
 
Trying to extract things out usually turned into a can of worms, and you
ended up with obviously contrived code, ruining the tidy structure of
your project.
 
(My solutions tended to use ad hoc manual declarations, circumventing
the module system, but the compiler could not check that my manual
declaration matched the actual definition of a function.)
 
Again, this itself turns into the problem that needs to be fixed. You
should be able to just write things in the most natural manner. If it
makes sense to the person reading or writing the code, it should make
sense to a compiler.
 
--
bart
 
enum (a=0,b,c=y,d) # usually 1-based
enum (w=b,x,y,z)
 
println a,b,c,d, w,x,y,z
 
 
Output:
 
0 1 3 4 1 2 3 4
 
This however doesn't work:
 
enum (a=b, b=a)
"Öö Tiib" <ootiib@hot.ee>: Jan 31 06:42AM -0800

On Thursday, 31 January 2019 13:47:41 UTC+2, James Kuyper wrote:
> completely independent of the distinction between "prototyped
> declaration" and "non-prototyped declaration" (with the latter appearing
> only in C).
 
The "prototypes" are typically denoting alternative to "classes"
in OOP languages with dynamic types. There instead of inheritance
we just extend objects directly and instead of instantiations
of classes we just clone prototype objects. That has not much
to do with C or C++, closest such language is JavaScript.
David Brown <david.brown@hesbynett.no>: Jan 31 04:38PM +0100

On 31/01/2019 12:47, James Kuyper wrote:
> completely independent of the distinction between "prototyped
> declaration" and "non-prototyped declaration" (with the latter appearing
> only in C).
 
Fair enough - that is a lot more precise than I was (and, I think more
precise than necessary). I referred to "prototypes" merely because some
people like to give a function prototype as a forward declaration, and
then omit the function parameters (if any) later in the definition.
David Brown <david.brown@hesbynett.no>: Jan 31 04:50PM +0100

On 31/01/2019 13:06, Bart wrote:
> trying to solve! And sometimes you can't neatly get around it:
 
>   enum {a,b,c=y,d};
>   enum {w=b,x,t,z};
 
It solves it for functions and types. It has never occurred to me that
anyone would have need of re-ordering enums like that. I think it could
be hard to get any solution here that does not involve multiple rounds
or general equation solving, which is hardly appropriate for a language
like C or C++. (You can do it in metafont or metapost, but those are
very different kinds of language.)
 
 
> Co-recursion has some technical meaning which I'm not sure is the one
> that is relevant here. If you mean that A() calls B() which calls A(),
> then I write such code all the time.
 
Mutual recursion is the term I wanted. There can be cases where this is
useful, in handling recursive data structures, but I think if you are
writing it a lot you have questionable coding structures. (Not
necessarily wrong, merely questionable.) However, the point is that is
only with such mutual recursion that you need to have forward
declarations for your functions - and it is not a hardship to use this
on occasion. It would be annoying to have to use forward declarations
for a large proportion of functions, but not for just a few.
 
> desirable:
 
>  E readexpr(void) { ... return readterm();}
>  E readterm(void) { ... return readexpr();}
 
I quite agree that it would be convenient to be able to do this without
forward declarations, and I can well understand allowing it in a new
language. I just don't think it is a big issue - like many people, I
have programmed in C (and other languages that need forward
declarations) for many years without feeling this to be a concern.
 
 
>> Mutually dependent imports (circular imports) are an issue, but these
>> can almost always be avoided in your code structuring.
 
> I've had experience of this and often found it difficult to impossible.
 
Maybe you have a fundamentally different way of organising code than I
do. (I know we have quite different types of code). It simply doesn't
occur in my coding - either embedded C, C++ and assembly programming, or
PC programming in Python, Pascal, etc.
 
jameskuyper@alumni.caltech.edu: Jan 31 08:02AM -0800

On Thursday, January 31, 2019 at 10:38:30 AM UTC-5, David Brown wrote:
> precise than necessary). I referred to "prototypes" merely because some
> people like to give a function prototype as a forward declaration, and
> then omit the function parameters (if any) later in the definition.
 
Could you demonstrate the technique you're talking about? I suspect that you've not describing it correctly. If function parameters are present in a forward declaration of a function, but omitted from the corresponding function definition, then:
 
1. In C++ you've defined an overload of the function with a different signature from the one used in the forward declaration - calling the function with arguments that match the forward declaration would result in a search (which would presumably fail) for a different overload.
 
2. In C, you've defined a function that's incompatible with the forward declaration. That's a constraint violation if they have the same scope (6.7p3), and the behavior is undefined (6.2.7p2), regardless of scope.
Bart <bc@freeuk.com>: Jan 31 08:42PM

On 31/01/2019 15:50, David Brown wrote:
 
> Mutual recursion is the term I wanted. There can be cases where this is
> useful, in handling recursive data structures, but I think if you are
> writing it a lot you have questionable coding structures.
 
No it's not questionable. Most of the big programs I've written have
involved recursive data. (CAD systems, windows-based GUIs, compilers and
interpreters. Even file systems are recursive.) Obviously yours don't.
 
(Not
> declarations for your functions - and it is not a hardship to use this
> on occasion. It would be annoying to have to use forward declarations
> for a large proportion of functions, but not for just a few.
 
I had to do that for years. I can tell you that things are much sweeter
if you don't have to bother. (It's quite a problem too if you have one
language which or may not need forward declarations that has to be
expressed in one which has its own rules for them.)
 
> language. I just don't think it is a big issue - like many people, I
> have programmed in C (and other languages that need forward
> declarations) for many years without feeling this to be a concern.
 
I like to add functions in any order. I shouldn't have to consider that
the functions one may call are always defined earlier, or that the
functions that might call this one must be defined later. How do you
even find that spot in a busy module?
 
And you might want to move things around, or copy code between files.
 
 
 
>> I've had experience of this and often found it difficult to impossible.
 
> Maybe you have a fundamentally different way of organising code than I
> do.
 
Let's take one project of mine (not C code obviously as it uses
modules), and look at two modules mc_name and mc_type (two successive
passes of a compiler). mc_name has this at the top:
 
import mc_type
 
And mc_type has this:
 
import mc_name.
 
Mutual imports. According to you, I should be able to trivially fix
that. Those modules ought to be independent, but sometimes things aren't
perfect.
 
mc_name calls one function in mc_type, but I can't just extract that
into a third module, as it has numerous connections to the rest of the
module. And it's the same story the other way. And unless I have /two/
extra new modules, I would be mixing up the gubbins from what are
supposed to be two unrelated modules, and exposing even more stuff that
is supposed to be kept private to each.
 
One more project where the two modules are cc_lex and cc_lib (a C
compiler). And it's the same thing where rearranging things so that the
modules are a pure hierarchy would mean tearing the project apart and
having a weird module structure that now needs an explanation.
 
(As I said, I solved this in the past by just adding a few manual
function declarations to cut across module demarcations. Now it is
easier for them just to import each other. It works fine.)
Melzzzzz <Melzzzzz@zzzzz.com>: Jan 31 09:07PM


> No it's not questionable. Most of the big programs I've written have
> involved recursive data. (CAD systems, windows-based GUIs, compilers and
> interpreters. Even file systems are recursive.) Obviously yours don't.
 
List is recursive data structure, so as tree and any graph for that
matter... are you sure you are arguing right thing?
 
--
press any key to continue or any other to quit...
Thomas Koenig <tkoenig@netcologne.de>: Jan 31 09:17PM

>>    https://vector-of-bool.github.io/2019/01/27/modules-doa.html
 
>> Cool, the author compared C++ to Fortran !
 
> Not in a way that said something good about C++ modules. :(
 
Not that there are a lot of good things to be said about the C++
module proposal. The question of which module is defined
in which file (well, you could put it into a Makefile when you
write it) is only one aspect. Another aspect is the question
of how to handle #defines which are in force when a module is
used...
Bart <bc@freeuk.com>: Jan 31 09:42PM

On 31/01/2019 21:07, Melzzzzz wrote:
>> interpreters. Even file systems are recursive.) Obviously yours don't.
 
> List is recursive data structure, so as tree and any graph for that
> matter... are you sure you are arguing right thing?
 
In the sorts of languages we're talking about, you would probably use
iteration for lists and recursion for anything that looks like a tree
because those would be the most practical choices.
 
But if you are going to add lists to the set of recursive data
structures, then that would just increase the number of programs that
use mutual recursion.
Melzzzzz <Melzzzzz@zzzzz.com>: Jan 31 10:33PM


> But if you are going to add lists to the set of recursive data
> structures, then that would just increase the number of programs that
> use mutual recursion.
 
Yeah list is first class citizen in recursive languages.
 
--
press any key to continue or any other to quit...
"Öö Tiib" <ootiib@hot.ee>: Jan 31 01:34AM -0800

On Wednesday, 30 January 2019 19:52:01 UTC+2, Daniel wrote:
> pedantry and usefulness, yet those decisions make the difference between a
> product that is accepted, and one that is not. Your comments appreciated, as
> always.
 
I forgot to tell that if you want to support wide variety of texts
in interface like ...:

auto s = j.as<std::basic_string<AnyChar,AnyTraits,AnyAllocator>>();
 
... then that might be is too ambitiously configurable in call site. What
it has to do may be very different based on what is the asked as return
type and how type of j was configured, what is platform and
compiler defines. So interface like ...
 
auto a = j.to_utf8();
auto b = j.to_ucs4();
auto c = j.to_nsstring();
auto d = j.to_qstring();
auto e = j.to_bstr();
 
... can be extended piece by piece and on need or feature request
basis and can even refuse to compile on each platform or with every
set of switches. Say NSString makes sense only on OSX/iOS, _bstr_t
only in Windows and QString only when Qt is used.
That might simplify the issue for all of writers, testers, profilers and
callers of those and that will help to concentrate on those interested
and provide value faster to them.
Daniel <danielaparker@gmail.com>: Jan 31 07:06AM -0800

On Thursday, January 31, 2019 at 4:34:14 AM UTC-5, Öö Tiib wrote:
 
> ... can be extended piece by piece and on need or feature request
> basis
 
Good advise, generally.
 
Anyway, I've decided not to continue with experimental version (**). I've concluded that the experimental version would benefit no users, would annoy some, and would introduce the possibility of encoding exceptions everywhere instead of just at the endpoints.
 
Daniel
Vir Campestris <vir.campestris@invalid.invalid>: Jan 31 09:46PM

On 28/01/2019 15:24, Scott Lurndal wrote:
> of the hardware and test software. No spinning rust can provide those datarates; you have
> to go to high end NVMe SSD setups. Do include measurements of the system overhead
> when compared with using lower-overhead I/O mechanisms like mmap or O_DIRECT.
 
Scott if his speeds are unbelieveably fast for his hardware - maybe he
is running out of cache. But so what? It means he isn't bound by the
hardware, and they are reflecting his I/O overheads.
 
Andy
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jan 31 02:07AM +0100

On 30.01.2019 17:59, Richard wrote:
>> through the odd spammer's comment, but not so much that it's a problem.
 
> I've had very good results rejecting spam through wordpress.com, so it
> is possible to configure wordpress to be very good at rejecting spam.
 
Oh. I didn't even know one could do that.
 
Re the code I posted it was ugly, just the first the worked,
unreasonably half-way between two reasonable solutions. For consecutive
enum values it would be simpler and more efficient to generate a
`switch`. And for the case of wanting two-way conversion or ability to
iterate over value/string pairs, the collection of value/string pairs
should be provided on its own and not just a local static in a function.
 
The OP has still not turned on commentary, but has posted summaries and
one full quote of commentary he's received on Reddit. That approach did
/not/ work out well. I mentioned, in the posting up-thread, that lack of
commentary function on the blog could lead to
 
> incorrect stuff will not be corrected, improvements and alternatives
> will not be available
 
and just that has happened. :(
 
In particular, the January 27 posting "shrink_to_fit that doesn't suck"
still provides only solutions (to a non-existing problem) that do suck,
and the January 30 posting "What happens when we "new"" incorrectly and
misleadingly states that when one writes
 
T* t1 = new T;
 
the compiler allegedly translates that to (really, it does NOT force use
of the global allocation function)
 
T* t2 = (T*)::operator new(sizeof(T));
try
{
new (t2) T;
}
catch(...)
{
::operator delete(t2);
throw;
}
 
The incorrect belief in that correspondence was once the basis of an
infamous bug in Microsoft's MFC framework, where one could get a memory
leak that manifested only in debug builds.
 
So, it seems we have a new C++ blog that provides some misleading
dis-information, sort of like Herb Schildt, with commentary turned off. :(
 
 
Cheers!,
 
- Alf
mvorbrodt@gmail.com: Jan 30 06:00PM -0800

On Wednesday, January 30, 2019 at 8:08:11 PM UTC-5, Alf P. Steinbach wrote:
> dis-information, sort of like Herb Schildt, with commentary turned off. :(
 
> Cheers!,
 
> - Alf
 
the comments are open on the blog. please post corrections. if I put misleading information I want to learn and correct it.
mvorbrodt@gmail.com: Jan 30 06:01PM -0800

On Tuesday, January 29, 2019 at 10:23:53 PM UTC-5, Alf P. Steinbach wrote:
> --------------------------------------------------------------------------
 
> Cheers!,
 
> - Alf
 
the comments are open on the blog. please post corrections. if I put misleading information I want to learn and correct it.
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: