Wednesday, June 19, 2019

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

rick.c.hodgin@gmail.com: Jun 19 06:18AM -0700

Why doesn't C++ allow a function overload by the return type?
Outwardly, it seems to be an arbitrary constraint.
 
--
Rick C. Hodgin
Bart <bc@freeuk.com>: Jun 19 02:27PM +0100

> Why doesn't C++ allow a function overload by the return type?
> Outwardly, it seems to be an arbitrary constraint.
 
Not familiar with function overloads in C++, but assuming you can have
one f(int,int) that returns type T, and another f(int,int) that returns
type U, which function is called here:
 
cout << f(10,20);
 
?
rick.c.hodgin@gmail.com: Jun 19 06:46AM -0700

On Wednesday, June 19, 2019 at 9:27:35 AM UTC-4, Bart wrote:
> type U, which function is called here:
 
> cout << f(10,20);
 
> ?
 
It wouldn't matter, because in that context any input value can
be used, which means any return type T or U can be used. Either
could be chosen and have it work. If you needed a specific one,
then:
 
cout << (U)f(10,20);
 
In other cases, it would be contextual based on its use in the
calling function. If it returned type T=int in one case, an
type U=float in another:
 
if (f(1, 2) == 3) // Assume int return type
if (f(1, 2) == 3.0f) // Assume float return type
 
In other cases it would be returning a class or struct. I can
see it working in all cases except where there's ambiguity.
 
struct SType1
{
int x;
int value;
};
 
struct SType2
{
int y;
int value;
};
 
// Return type overload
SType1* f(void);
SType2* f(void);
 
// Use in code
f()->x; // No ambiguity
f()->y; // No ambiguity
f()->value; // Ambiguity, generate a diagnostic
((SType1*)f())->value; // No ambiguity
((SType2*)f())->value; // No ambiguity
 
--
Rick C. Hodgin
Bart <bc@freeuk.com>: Jun 19 03:05PM +0100


>> ?
 
> It wouldn't matter, because in that context any input value can
> be used, which means any return type T or U can be used.
 
If could matter because the two functions could do different things and
you might specifically want one. (Or may not even be aware of the other.)
 
 
Either
> could be chosen and have it work. If you needed a specific one,
> then:
 
> cout << (U)f(10,20);
 
That doesn't really fix it. Which function is called which is then cast
to U? Use of a cast suggests the return type is something other than U,
so either function could plausibly be called.
 
> type U=float in another:
 
> if (f(1, 2) == 3) // Assume int return type
> if (f(1, 2) == 3.0f) // Assume float return type
 
 
This doesn't follow. And actually you've hit on other problems:
 
f(1,2) / f(3,4)
 
Which version of f is used for each operand? The possible combinations
are int/int, int/float, float/int, float/float, with different results.
Now it can depend on how "/" is used! And that only differentiates
between int/int (int result) and the rest (all float).
 
Suppose there are also 2 g functions; one is g(int,int)->int, and the
other is g(float,float)->float. Which g is called here:
 
g(f(1,2),f(3,4)) ?
 
 
> f()->value; // Ambiguity, generate a diagnostic
> ((SType1*)f())->value; // No ambiguity
> ((SType2*)f())->value; // No ambiguity
 
Is this speculation for a feature in your new language?
rick.c.hodgin@gmail.com: Jun 19 07:18AM -0700

On Wednesday, June 19, 2019 at 10:05:41 AM UTC-4, Bart wrote:
 
> That doesn't really fix it. Which function is called which is then cast
> to U? Use of a cast suggests the return type is something other than U,
> so either function could plausibly be called.
 
In the case of an overloaded return type, the cast would be used
as a cue to determine which function to call. If there is one
which returns that type, then use that one. If not, then look
for suitable candidates and pick one generating a warning diag-
nostic. If none are suitable, generate an error diagnostic.
 
> > if (f(1, 2) == 3.0f) // Assume float return type
 
> This doesn't follow. And actually you've hit on other problems:
 
> f(1,2) / f(3,4)
 
It is ambiguous and would generate a warning diagnostic.
 
 
> Suppose there are also 2 g functions; one is g(int,int)->int, and the
> other is g(float,float)->float. Which g is called here:
 
> g(f(1,2),f(3,4)) ?
 
It is ambiguous and would generate a warning diagnostic.
 
> > ((SType1*)f())->value; // No ambiguity
> > ((SType2*)f())->value; // No ambiguity
 
> Is this speculation for a feature in your new language?
 
No. I had need of this today. I wound up writing a marshaling
function to handle the variable return types for me transparently
to my use in code.
 
This is how I come up with these ideas most of the time. I'm
coding something, and in the midst of me coding I see how it
could be done differently there in the moment. I consider it
for a time and if it seems plausible I add it to my language,
and if it's not so cut and dry I come here and ask questions.
 
I think an overloaded type could be of benefit. I may be of
greater use like this:
 
String f(int, int);
Integer f(int, int);
 
Where the return types are so solidly different that it is then
obvious which one to use in context. And where it is ambiguous,
use a cast to indicate which one you want. It might even be a
desirable thing to create a new auto-cast syntax for the over-
loaded return type to something like this:
 
String.f(1,2); // When you explicitly need the String f()
Integer.f(1,2); // When you explicitly need the Integer f()
 
I think I will add overloaded return types to CAlive, but it's
not a priority. I already support multiple return values using
a different function prototype syntax:
 
function name
| params int a, int b
| returns char* c, float d, double e
{
// Reference the return values by name, as they
// generally appear like local variables
c = null;
d = 0.0f;
e = 0.0;
 
// Or issue a hard return statement like this:
return { null, 0.0f, 0.0 };
 
// If you're only filling partial slots with new
// information, use the nocode keyword (used so
// you indicate there is no code there, and that
// it's on purpose, and not just something you
// forgot):
c = null;
e = 0.0;
return { nocode, 0.0f, nocode };
}
 
--
Rick C. Hodgin
jameskuyper@alumni.caltech.edu: Jun 19 07:53AM -0700

> Why doesn't C++ allow a function overload by the return type?
> Outwardly, it seems to be an arbitrary constraint.
 
Because the overload to be called is chosen based upon the types of the
arguments passed to the function. If those types aren't different
between two overloads, it can't determine which one to use.
 
This is intimately related to a key principle that guided the design of
C++, which was inherited from C: what an expression does when evaluated
is determined entirely by the expression itself, not by the context it
occurs in. How the result of that evaluation is handled does depend upon
the context, but the evaluation itself does not.
 
That statement does not quite say what I mean, and the simplest way I
can come up with to correct it is to explain how it's wrong. The set of
identifiers that are currently in scope is part of the context, and has
a great deal of effect on how an expression is evaluated. However, if
an expression is a sub-expression of another expression, the containing
expression has no effect on how the sub-expression is evaluated. If an
expression is a full-expression, it is necessarily part of some other
piece of syntax, such as an if() statement. The fact that an if()
statement's condition must be convertible to bool, for instance, does
not influence how the expression is evaluated - it only determines
whether or not the result of that evaluation is acceptable.
 
This principle makes it easier to think about the meaning of C++ code,
and I suspect it makes it easier to compile, too. I wouldn't hold up too
much hope of convincing the C++ committee to make a decision that would
violate this principle.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 18 08:01PM -0400

On 6/18/19 6:24 PM, Ben Bacarisse wrote:
>> your proposed change.
 
> Currently, strcmp(stringOne, stringTwo) returns 0 when the strings are
> equal. The OP is proposing a change so that this would be 1.
 
I responded too quickly, without reading carefully enough. I assumed his
proposal was more sane than it actually was.
I should have said that "if(!strcmp(stringOne,stringTwo)) does the same
thing under the G G's proposal that if(strcmp(stringOne,stringTwo))",
with corresponding changes to the other comments I made.
 
Furthermore, I should have been more emphatic about the impossibility of
getting this changed - this will not merely break a lot of existing code
that uses strcmp() - it will break all existing code that uses it.
Keith Thompson <kst-u@mib.org>: Jun 18 06:03PM -0700


> given strings : stringOne, stringTwo are equal
 
> that strcmp( stringOne, stringTwo ) will return true with a value of 1 or
> bool = true
 
No, because it would break existing code.
 
The result of strcmp() is not a boolean (yes/no, true/false) value.
It's a *number*, with different meanings for negative, zero, and
positive values.
 
I do see the advantages of having boolean string comparison functions
that work like the <, <=, ==, !=, >, and >= operators on scalars. And I
personally dislike code that treats strcmp()'s result as if it were
boolean, such as:
if (!strcmp(s1, s2) /* s1 and s2 equal */
 
If you really want boolean comparisons for strings you can roll your own:
 
#define STR_EQ(s1, s2) (strcmp((s1), (s2)) == 0)
#define STR_NE(s1, s2) (strcmp((s1), (s2)) != 0)
#define STR_LT(s1, s2) (strcmp((s1), (s2)) < 0)
#define STR_LE(s1, s2) (strcmp((s1), (s2)) <= 0)
#define STR_GT(s1, s2) (strcmp((s1), (s2)) > 0)
#define STR_GE(s1, s2) (strcmp((s1), (s2)) >= 0)
 
But with more experience working with C, I think you'll find that
these macros just aren't necessary. Any C programmer who has worked
with strings knows how strcmp() works, and can read `strcmp(s1, s2)
< 0` as easily as `STR_LT(s1, s2)`. In fact, the strcmp() version
is probably easier to read, because it doesn't require finding and
understanding the macro definition.
 
If a future version of the language added standard streq(), strne(),
et al as functions (possibly implemented as macros) to <string.h>,
I wouldn't object, but I doubt that's going to happen.
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 19 06:02AM +0200

On 18.06.2019 23:36, G G wrote:
 
> and maybe a new function strcmpOrder( string string1, string string2 )
> where if string1 comes before string2 returns a 1
 
> if not return 0;
 
The functions you mention are for comparing C strings, zero-terminated
strings represented by pointers.
 
Up at the C++ level `strcmp` corresponds to `std::string::compare`.
 
But `std::string` also offers the usual relational operators, like `==`,
`>` and so on, and the easiest way to get that notation for strings is
to just use `std::string`.
 
 
 
> lol
 
> there is probably something better to come 14 more chapters to go.
 
> :-)
 
Hm, which book?
 
Anyway, the `strcmp`, `memcmp`, `std::string::compare` family of
functions, or at least the concept they embody, are about to have a
renaissance with the introduction of the spaceship operator in C++20.
 
The concept is roughly this: since the non-zero result values are not
specified one can use *any* values, and for example lexicographically
compare two struct instances this way:
 
struct S{ int x; int y; int z; };
 
auto compare( const S& a, const S& b )
-> int
{
if( const int r = a.x - b.x ) { return r; }
if( const int r = a.y - b.y ) { return r; }
if( const int r = a.z - b.z ) { return r; } // Redundant, but.
return 0;
}
 
Then the relational operators can easily and efficiently be expressed in
terms of, and automatically generated from, the single compare function.
 
A manual definition of one of them:
 
auto operator<( const S& a, const S& b )
-> bool
{ return compare( a, b ) < 0; }
 
If you try to express this function directly, without a function like
compare doing the brunt work, then you get into complexity where it's
very easy to step wrong, and then e.g. standard collections don't work.
 
That problem is reduced, though, when one learns about the `std::tuple`
based workaround,
 
auto operator<( const S&a, const S&b )
-> bool
{
using std::tie;
return tie( a.x, a.y, a.z ) < tie( b.x, b.y, b.z );
}
 
Here the `std::tuple::operator<` does the work, guaranteed correctly,
although possibly not as efficiently as compare. But on the third hand
with modern computers efficiency is no longer a matter of counting basic
operations. So it might be just as efficient, or even more.
 
It's just very much more work to do, with much redundancy, in general.
 
 
Cheers & hth.,
 
- Alf
queequeg@trust.no1 (Queequeg): Jun 19 10:26AM


> I doubt it. You might have to make your own functions, eg:
 
True.
 
> int streq(char* s, char* t) { return strcmp(s,t)==0;}
> int strlt(char* s, char* t) { return strcmp(s,t)<0;}
 
But please, please, please, use const in such situations. I've seen too
many functions that obviously don't modify the string, but don't care
about const, and it breaks the program logic.
 
Consider:
 
static void function(const char *argument)
{
static const char * const test = "test";
if (streq(argument, test))
{
// ...
}
}
 
--
https://www.youtube.com/watch?v=9lSzL1DqQn0
Juha Nieminen <nospam@thanks.invalid>: Jun 19 10:34AM


> given strings : stringOne, stringTwo are equal
 
> that strcmp( stringOne, stringTwo ) will return true with a value of 1 or
> bool = true
 
No. On the contrary, the upcoming operator<=> will rely on the implementation
using exactly that kind of results for comparisons.
 
There's a reason for that.
Manfred <noname@add.invalid>: Jun 19 02:01PM +0200

On 6/18/2019 11:36 PM, G G wrote:
 
> lol
 
> there is probably something better to come 14 more chapters to go.
 
> :-)
 
As others have said, there's no chance for such a change.
In addition to being a breaking change for zillions of lines of existing
code, strcmp yields more than an equality test, it also delivers total
ordering on strings, which is a widely required feature.
And the implementation of strcmp yields ordering with zero extra cost
compared to a pure equality test.
shahla yavari <shahlayavari3@gmail.com>: Jun 18 08:13PM -0700

(∂(hc_i))/∂t+(∂(〖qc〗_i))/∂x =e_i+e_di+r_i 〖+r〗_ri-d_i,
Real Troll <real.troll@trolls.com>: Jun 19 12:35AM -0400

On 19/06/2019 04:13, shahla yavari wrote:
> (∂(hc_i))/∂t+(∂(〖qc〗_i))/∂x =e_i+e_di+r_i 〖+r〗_ri-d_i,
 
Please start here first:
 
<https://www.codeproject.com/Articles/43607/Solving-ordinary-differential-equations-in-C>
 
You need to learn how to use Google Search Engine as it has most answers
to get started.
 
Good luck.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 19 07:53AM -0400

On 6/18/19 11:13 PM, shahla yavari wrote:
> (∂(hc_i))/∂t+(∂(〖qc〗_i))/∂x =e_i+e_di+r_i 〖+r〗_ri-d_i,
 
You need a symbolic math package to handle such equations in that form.
The two I'm most familiar with are called Mathematica and Maple. I
haven't used such packages in a long time, so it's entirely possible
that there's more modern symbolic math systems that are much better than
those.
 
While you can't handle such equations in that form in C++, it's possible
to write C++ code to solve partial differential equations numerically. A
key concept in putting together such solutions is to approximate the
partial derivatives with finite-differences: the partial derivative of
f(x,y) with respect to x at the point x0,y0 can be approximated by
(f(x0+deltax,y0) - f(x0,y0))/deltax, where deltax is the spacing of your
discrete approximation to f in the x direction.
 
However, you don't have a well-posed problem until you've specified
boundary conditions for the solution - the fact that you didn't mention
any suggests that you're not quite ready to do something like that.
 
There's lots and lots of subtleties that need to be dealt with. For
instance, it's quite easy to misuse finite-difference approximations to
justify an algorithm for solving the equations that, instead of
converging on a valid solution, diverges exponentially away from a valid
solution. You need to take some courses and/or read some advanced books
on numerical methods before even attempting to do such things.
Alan Mackenzie <acm@muc.de>: Jun 19 11:11AM

Release Announcement
CC Mode Version 5.34
Alan Mackenzie
 
This message announces the availability of a new version of CC Mode,
an Emacs and XEmacs mode for editing C (ANSI and K&R), C++,
Objective-C, Java, CORBA's IDL, Pike and AWK code.
 
A list of user visible changes is detailed in the NEWS file and in the
URL listed below. More information, including links to download the
source, are available on the CC Mode web page:
 
<http://cc-mode.sourceforge.net/>
 
Send email correspondence to
 
bug-cc-mode@gnu.org
 
For a list of changes please see
 
<http://cc-mode.sourceforge.net/changes-534.php>
 
--
Alan Mackenzie (Nuremberg, Germany).
Juha Nieminen <nospam@thanks.invalid>: Jun 19 10:40AM

If I had been asked if this compiles, I would have answered "no".
 
At least clang disagrees with me. I assume it's right. And I'm both
wrong and very confused.
 
//---------------------------------------------------------
#include <iostream>
 
namespace ANamespace
{
struct Data
{
int mValue;
bool operator<(const Data&) const;
};
}
 
class AClass
{
public:
using Inner = ANamespace::Data;
};
 
// This compiles???
bool AClass::Inner::operator<(const Data& rhs) const
{
return mValue < rhs.mValue;
}
 
int main()
{
AClass::Inner d1 { 5 }, d2 { 10 };
std::cout << (d1 < d2) << "\n";
 
ANamespace::Data d3 { 20 }, d4 { 15 };
std::cout << (d3 < d4) << "\n";
}
//---------------------------------------------------------
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 18 08:05PM -0400

On 6/18/19 7:20 PM, G G wrote:
> depending on the cpu, clock cycles... is it somehow
> assigned or read and calculated from the bios or uefi.
 
> ctime / time.h header files
 
CLOCKS_PER_SEC is a macro "which expands to an expression with type
clock_t" (7.27.1p2). That description allows for the possibility that it
expands into a function call, which might do any of the things you're
talking about.
Keith Thompson <kst-u@mib.org>: Jun 18 07:01PM -0700

> depending on the cpu, clock cycles... is it somehow
> assigned or read and calculated from the bios or uefi.
 
> ctime / time.h header files
 
The CLOCKS_PER_SEC macro yields the precision of the value returned
by the clock() function. It doesn't *necessarily* correspond to
any physical characteristic of the system. An imaginary example:
if CLOCKS_PER_SEC is one million (as it is on POSIX systems),
the value returned by clock() represents a number of microseconds,
but it might always be a multiple of 1000, indicating an underlying
resolution of 1 millisecond.
 
As James Kuyper points out, the standard's definition of
CLOCKS_PER_SEC allows it to vary (though presumably it would keep the
same value for a run of a program), but on many (most?) systems it's
defined as a constant. In fact, I'd be at least mildly surprised
if there were a system with CLOCKS_PER_SEC not defined as a constant.
 
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
Juha Nieminen <nospam@thanks.invalid>: Jun 19 10:37AM

> compilers and cpu and clock cycles can be different
> depending on the cpu, clock cycles... is it somehow
> assigned or read and calculated from the bios or uefi.
 
Even if CLOCKS_PER_SEC is, for example, 1000, that doesn't mean you
are going to get the timing at 1ms of accuracy. The values may well
jump by more than 1.
 
That value only indicates what you need to divide std::clock() by
in order to get seconds. It doesn't indicate what the accuracy
of that function is. (It may well be more or less accurate than
that.) Internally, whatever the system uses will get scaled
so that the multiplier will be CLOCKS_PER_SEC.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 18 07:57PM -0400

On 6/18/19 8:49 AM, Paavo Helde wrote:
...
> For emulating a stack std::deque would be a better option than std::vector.
 
Why?
 
Actually, I'd think that
std::stack<T, std::vector<T> > would be slightly better for emulating a
stack: it would allow you to use push() and pop().
Melzzzzz <Melzzzzz@zzzzz.com>: Jun 19 04:29AM


> Actually, I'd think that
> std::stack<T, std::vector<T> > would be slightly better for emulating a
> stack: it would allow you to use push() and pop().
 
There is no point. Local variables and constants cannot be placed in
that vector. We will always depend on stack size being limited.
Compiler can always use segmented stacks, but alas for performance
reasons they don't want to do that....
 
 
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
Paavo Helde <myfirstname@osa.pri.ee>: Jun 19 08:38AM +0300

On 19.06.2019 2:57, James Kuyper wrote:
> ...
>> For emulating a stack std::deque would be a better option than std::vector.
 
> Why?
 
The same reasons why std::stack defaults to using std::deque underneath.
With a stack you typically only work with a small part of it, std::deque
ensures that small parts are compact in memory, and at the same time it
does not waste time on reallocating and copying over all elements when
it needs to grow.
 
OTOH, std::deque has a bit more indirection when accessing the elements,
which might or might not be significant.
 
Anyway, the choice depends on the usage case and should be
measured/profiled.
 
 
> Actually, I'd think that
> std::stack<T, std::vector<T> > would be slightly better for emulating a
> stack: it would allow you to use push() and pop().
 
I have often tried to use std::stack, then discovered I still need to
access elements beneath top(), and switched over to plain std::deque or
std::vector.
David Brown <david.brown@hesbynett.no>: Jun 19 11:18AM +0200

On 19/06/2019 06:29, Melzzzzz wrote:
> that vector. We will always depend on stack size being limited.
> Compiler can always use segmented stacks, but alas for performance
> reasons they don't want to do that....
 
Compilers /do/ use segmented stacks - with the right compiler, options,
target cpu, host OS, etc. Look up gcc's "split stack" feature for
example - and no doubt other compilers have support too. It is not a
feature you'd want without reason, as it complicates (and thus slows
down) the code - but in some cases it is worth using.
Melzzzzz <Melzzzzz@zzzzz.com>: Jun 19 04:26AM


>>> Not dead yet. Knocking on wood... :^)
>> You are not on Ultimate Good side already?
 
> I always try to be a nice person: Is that good enough?
 
Seems so ;)
 
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
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: