Tuesday, December 11, 2018

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

"Öö Tiib" <ootiib@hot.ee>: Dec 11 06:26AM -0800

On Tuesday, 11 December 2018 12:40:59 UTC+2, Paul wrote:
> > container and then one-pass counting is about as time-complex
> > as with sorting plus it takes double memory too. Your algorithm
> > below loses to all of those.
 
It is pity that you did ignore it.
 
> However, the technique doesn't work as well because it necessitates changing
> the return type which isn't ideal. I hadn't heard of std::optional -- many
> thanks for introducing this to me.
 
The whole point posting was to help you.
 
> The time complexity of my algorithm is O(N)
 
It is clearly not.
 
> by copy-pasting of a verified program (although you couldn't have known
> that). I would rather it didn't compile so that I could have uncovered this
> mistake myself. I should have just used a range-based for loop.
 
Yes, but more importantly it can be made one pass algorithm.
 
> You might be correct that "it looks something like O(N*log(N) + N*N)" but
> it is O(N) regardless of what it looks like.
> See Alf's post for more info.
 
Can you try to explain it a bit better? Telling instead that hashtable is
using hashing clarifies nothing of your line of thought.
Learn to explain things with your own words; I can't find support to
your O(N) in any of Alf's posts.
 
I can explain why your complexity "looks" what I said:
A) Complexity of constructor
https://en.cppreference.com/w/cpp/container/unordered_multiset/unordered_multiset
type 2) so linear to quadratic. Starting O formula:
 
O(N*something + ...
 
B) Complexity of for loop over all elements
That is linear. Adding to O forrmula:
 
O(N*something + N * ...
 
C) Complexity of calling count in for loop
https://en.cppreference.com/w/cpp/container/unordered_multiset/count
That is also linear to the number of equal elements.
 
O(N*something + N * M)
 
Where N is number of elements and M is number of equal
elements. That can't be reduced down to O(N) .... and looks expensive
so go ahead and explain why it is not that.
Paul <pepstein5@gmail.com>: Dec 11 07:03AM -0800

On Tuesday, December 11, 2018 at 2:26:19 PM UTC, Öö Tiib wrote:
 
> Where N is number of elements and M is number of equal
> elements. That can't be reduced down to O(N) .... and looks expensive
> so go ahead and explain why it is not that.
 
I'll repeat the (bugged because of the mix in iterators) code for convenience.
Comments about the time complexity will be interspersed with the code.
 
Ok, yeah, I can see it's not linear, now.
I was wrong. Mea culpa.
Yes, I always realised you were trying to help.
 
Paul
 
double DataStructuresMajority(const std::vector<int>& vec)
{
const double noMajority = 0.5;
std::unordered_multiset<int> duplicates(vec.begin(), vec.end()); // O(N)
for(std::unordered_set<int>::const_iterator iter = duplicates.begin(); iter!= duplicates.end(); ++iter)
if(duplicates.count(*iter) > vec.size()/2)
return *iter;
// Above is bugged -- wrong iterator type but still compiles and
// even seems to work.
// The count function is O(number of occurrences of element being counted)
return noMajority;
}
Jorgen Grahn <grahn+nntp@snipabacken.se>: Dec 11 08:02AM

On Tue, 2018-12-11, Paul wrote:
 
> No, but you're saying that you don't understand my code.
> For a multiset, using std::count rather than multiset::count()
> is a really bad idea.
 
I was referring to your first example problem. If the second one with
unordered_multiset was more important to you, I missed that fact.
 
> Thanks for not reading my post, and then complaining about what you
> didn't read.
 
Where am I complaining or saying I don't understand your code?
I was trying to be helpful.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Stuart Redmann <DerTopper@web.de>: Dec 11 09:04AM +0100


> Thanks for not reading my post, and then complaining about what you
> didn't read.
 
> Paul
 
I don't think that Jorgen did not get your point or did not understand your
problem, even though he wrote that he didn't read your posting to the very
end. I find Jorgen's answer quite informative, and BTW Jorgen does not
propose to use std::count on the implementation of at_least, he just left
the implementation empty as an (rather simple) exercise.
 
Jorgen probably misunderstood you in that regard that he thinks you, Paul,
were not able to roll your own version of at_least, but I'm pretty sure
that you are able to do so. You statement "I'm not sure how to proceed in
this case" is very likely meant as "I'm not sure how I can find out whether
the compiler will abort the loop prematurely or not."
 
So this is more or less a classic misunderstanding. However, I think that
your answer to Jorgen is a bit to disrespectful, with regard to Jorgen
being one of the top posters of this group. I'm just afraid that two
competent participants, Jorgen and you, might start to dislike one another
over a simple misunderstanding, which would be a pity.
 
Regards,
Stuart
Paul <pepstein5@gmail.com>: Dec 11 01:12PM -0800

On Tuesday, December 11, 2018 at 3:03:51 PM UTC, Paul wrote:
> // The count function is O(number of occurrences of element being counted)
> return noMajority;
> }
 
This is a correct O(n) implementation of the same basic idea.
double DataStructuresMajority(const std::vector<int>& vec)
{
const double noMajority = 0.5;
std::unordered_set<int> nonDuplicates(vec.begin(), vec.end());
std::unordered_multiset<int> duplicates(vec.begin(), vec.end());
for(int i : nonDuplicates)
if(duplicates.count(i) > vec.size()/2)
return i;
 
return noMajority;
}
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 11 11:05AM +0100

On 11.12.2018 07:50, Paul wrote:
 
>>> return noMajority;
>>> }
 
>> I'd sort the vector and just count run lengths.
 
<> Thanks, Alf
> the "big O" of an algorithm is of primary importance.
 
> Sorting the vector would be regarded as terrible because it
> uses an O(n log n) algorithm where linear time is available.
 
Well, in a situation of paid work, if whoever commissioned the work has
that opinion and e.g. refuses to pay, then of course.
 
But otherwise just keep things simple.
 
The cost of developing this code in a way that can be marginally more
efficient for a zillion values, and the costs of maintenance of that
more than necessary complex code, likely far outweighs the gains from
possibly running it once on a zillion items.
 
 
> a condition like m.count(3) > 4; where m is an unordered_multiset<int>?
> I suppose an approach might be to research how count() works and then
> modify it.
 
For b.count(k) for an unordered associative container b, C++17 table 91,
in §26.2.7, gives complexity requirements average case O(b.count(k)) and
worst case O(b.size()).
 
In §20.4.1.4 it's explained that "Complexity requirements specified in
the library clauses are upper bounds, and implementations that provide
better complexity guarantees satisfy the requirements."
 
The problem with an /unordered/ container is that there's no way to
select only the key values = k that you're interested in, for the
purpose of counting them. An ordered container gives you that, but at
the cost of a log(n) factor of complexity. So you're into trade-offs,
which can be interesting. :)
 
 
Cheers!,
 
- Alf
leigh.v.johnston@googlemail.com: Dec 11 04:28AM -0800

On Tuesday, December 11, 2018 at 10:47:02 AM UTC, Dawid Bautsch wrote:
> What happened to this project? Is it already dead? I can't see any activity on the forum as well on the main page.
 
Far from it. Inactivity on the forum is unsurprising given the library is still pre-release.
 
/Leigh
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Dec 11 01:11PM -0800

On 12/8/2018 4:05 PM, Mr Flibble wrote:
 
>> A chat program intermingled with something like ShaderToy, would be nice.
 
> That would be possible via scripting; I plan on having the graphics API
> available to scripts and that would include shader access.
 
That would be great. Thanks.
Michael Powell <mwpowellhtx@gmail.com>: Dec 11 06:10AM -0800

Hello,
 
I posted on SO, but I thought I should post through some group mailing lists as well.
 
http://stackoverflow.com/questions/53725676/latest-visual-c-runtime-class-destructors-a-little-too-aggressive
 
Basically, I am observing that dtors are being invoked much earlier than the end of scope when I would expect, even in debug mode. If it were a "release mode" I might understand that this sort of optimization, I gather, would take place, but not in debug mode.
 
What's the point of having a dtor if the scope is not respected by the compiler?
 
Thanks in advance for any insights.
 
Best regards,
 
Michael Powell
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 11 03:24PM +0100

On 11.12.2018 15:10, Michael Powell wrote:
 
> Basically, I am observing that dtors are being invoked much earlier than the end of scope when I would expect, even in debug mode. If it were a "release mode" I might understand that this sort of optimization, I gather, would take place, but not in debug mode.
 
> What's the point of having a dtor if the scope is not respected by the compiler?
 
> Thanks in advance for any insights.
 
The SO question does not include an example of the behavior, and a
number of comments there note that.
 
For posting the question here in clc++, please do read the FAQ item on
how to post such a question, "How do I post a question about code that
doesn't work correctly?", available at e.g. <url:
http://www.dietmar-kuehl.de/mirror/c++-faq/how-to-post.html#faq-5.8>.
 
I know of only one destructor invocation bug in current Visual C++,
namely related to C++ 17 inline variables; see <url:
https://developercommunity.visualstudio.com/content/problem/300686/static-inline-class-variables-have-their-destructo.html>.
 
 
 
Cheers!,
 
- Alf
Michael Powell <mwpowellhtx@gmail.com>: Dec 11 06:38AM -0800

On Tuesday, December 11, 2018 at 9:24:15 AM UTC-5, Alf P. Steinbach wrote:
 
> I know of only one destructor invocation bug in current Visual C++,
> namely related to C++ 17 inline variables; see <url:
> https://developercommunity.visualstudio.com/content/problem/300686/static-inline-class-variables-have-their-destructo.html>.
 
I appreciate the feedback. The question is really two-fold I think.
 
First to clarify the expectation, "when does one expect a dtor should be invoked?" I think at the end of scope, literally, either a statement i.e. ';' or end of a block i.e. '}'.
 
Then evaluating this is in fact a bug in the MSVC compiler; this bug does not seem to be that. For instance, assessing the actual behavior going on, I can "reason" that the instance is no longer used in the scope, but the compiler appears to interpret that as its trigger to invoke the dtor, most definitely much earlier than the end of its scope when I would expect. That is quite something different than multiple invocation in my opinion.
 
Paavo Helde <myfirstname@osa.pri.ee>: Dec 11 04:58PM +0200

On 11.12.2018 16:38, Michael Powell wrote:
 
> I appreciate the feedback. The question is really two-fold I think.
 
> First to clarify the expectation, "when does one expect a dtor should be invoked?" I think at the end of scope, literally, either a statement i.e. ';' or end of a block i.e. '}'.
 
> Then evaluating this is in fact a bug in the MSVC compiler; this bug does not seem to be that. For instance, assessing the actual behavior going on, I can "reason" that the instance is no longer used in the scope, but the compiler appears to interpret that as its trigger to invoke the dtor, most definitely much earlier than the end of its scope when I would expect. That is quite something different than multiple invocation in my opinion.
 
If a destructor was called earlier than its due time then it would
definitely be a major bug in the compiler. I do not believe even MSVC
would do this.
 
It is far more likely there is a bug in your own code, like creating
unnamed temporary variables which go out of scope immediately or
something like that. Please post an example.
 
hth
Paavo
Michael Powell <mwpowellhtx@gmail.com>: Dec 11 07:10AM -0800

On Tuesday, December 11, 2018 at 9:58:56 AM UTC-5, Paavo Helde wrote:
 
> It is far more likely there is a bug in your own code, like creating
> unnamed temporary variables which go out of scope immediately or
> something like that. Please post an example.
 
I can assure you this is no unnamed temporary, or I would not be here wasting your or my time. It is as my SO illustration indicates, a named local instance.
 
"Öö Tiib" <ootiib@hot.ee>: Dec 11 07:38AM -0800

On Tuesday, 11 December 2018 17:10:22 UTC+2, Michael Powell wrote:
> > unnamed temporary variables which go out of scope immediately or
> > something like that. Please post an example.
 
> I can assure you this is no unnamed temporary, or I would not be here wasting your or my time. It is as my SO illustration indicates, a named local instance.
 
I for one am interested to observe what you describe but I can't.
It just does not happen in my code in Visual Studio. So without
actual code example that compiles, links, runs and demonstrates
the issue I can't help you any. It is impossible to haggle or assure
me out of my ignorance of what you are talking about.
The users of SO seemed to be in same situation and so closed
your question with "unclear what you ask about".
Michael Powell <mwpowellhtx@gmail.com>: Dec 11 07:44AM -0800

On Tuesday, December 11, 2018 at 9:10:38 AM UTC-5, Michael Powell wrote:
 
> Basically, I am observing that dtors are being invoked much earlier than the end of scope when I would expect, even in debug mode. If it were a "release mode" I might understand that this sort of optimization, I gather, would take place, but not in debug mode.
 
> What's the point of having a dtor if the scope is not respected by the compiler?
 
> Thanks in advance for any insights.
 
One of the respondents to my SO question indicated this was most likely a confusion over "debugger code attribution". I am satisfied this is in fact the case.
 
My dtor was calling std::filesystem::remove(...) on a directory when I really needed to do a std::filesystem::remove_all(...). With the incorrect remove(...), that revealed itself as an exception, but the stack trace also had the dtor invocation happening much sooner than I expected it should be, hence the rabbit hole. Now with remove_all(...) things are much happier.
 
Thanks for the responses here helping to analyze the situation nonetheless.
 
scott@slp53.sl.home (Scott Lurndal): Dec 11 03:59PM

>ting your or my time. It is as my SO illustration indicates, a named local =
>instance.
 
>I for one am interested to observe what you describe but I can't.
 
 
I suspect in his case, MSVC may be running the destructor immediately after
the last use of the object, rather than waiting for the end of the scope which contains
it; should be perfectly legal under the as-is rule, right?
David Brown <david.brown@hesbynett.no>: Dec 11 05:11PM +0100

(Please get a proper news client instead of google groups. And if you
/must/ use GG, then at least split your lines at an appropriate length.
This is especially important when you post code - which you should do.)
 
On 11/12/18 15:38, Michael Powell wrote:
 
> First to clarify the expectation, "when does one expect a dtor
> should be invoked?" I think at the end of scope, literally, either a statement
> i.e. ';' or end of a block i.e. '}'.
 
Destructors are /logically/ called like that, in reverse order from
construction. But optimisation can re-order a lot of code, as long as
there is no change to the observable effect. Note that what you see
during debugging does not count as observable effects - compilers can
optimise code in "debug mode".
 
> invoke the dtor, most definitely much earlier than the end of its scope
> when I would expect. That is quite something different than multiple
> invocation in my opinion.
 
You have to post some code - as a self-contained snippet - before anyone
can help you. Otherwise we will simply assume there is a bug in /your/
code, or your understanding of C++, and that you are unable to ask
questions appropriately in order to get help. Once you post code, many
people will try to help. And ideally you should post a complete
compilable example, with minimal dependencies and minimal code, that can
be copied into <https://godbolt.org> for testing.
 
People in this group are happy to help, but only if you are willing to
give the required information.
"Öö Tiib" <ootiib@hot.ee>: Dec 11 08:17AM -0800

On Tuesday, 11 December 2018 17:59:57 UTC+2, Scott Lurndal wrote:
 
> I suspect in his case, MSVC may be running the destructor immediately after
> the last use of the object, rather than waiting for the end of the scope which contains
> it; should be perfectly legal under the as-is rule, right?
 
Compiler may do it when it can prove that the destructor does
not have side effects. Otherwise if destructor is say unlocking
mutexes, deleting files from file system or calling glPopMatrix()
then too early call will break majority of C++ code that I've seen.
David Brown <david.brown@hesbynett.no>: Dec 11 09:29PM +0100

On 11/12/2018 17:17, Öö Tiib wrote:
> not have side effects. Otherwise if destructor is say unlocking
> mutexes, deleting files from file system or calling glPopMatrix()
> then too early call will break majority of C++ code that I've seen.
 
Yes, but that would be against the as-if rule already.
 
The destructor is just like any other function call, placed at the right
point in the code (the end of the object's lifetime, ordered
appropriately with other destructors). And the exact time of executing
that call can be shuffled around like any other code, by the as-if rule,
as long as the compiler can see that the shuffling is safe and does not
disturb observable behaviour.
jameskuyper@alumni.caltech.edu: Dec 11 12:55PM -0800

On Tuesday, December 11, 2018 at 9:10:38 AM UTC-5, Michael Powell wrote:
> Hello,
 
> I posted on SO, but I thought I should post through some group mailing lists as well.
 
> http://stackoverflow.com/questions/53725676/latest-visual-c-runtime-class-destructors-a-little-too-aggressive
 
In that message, he states that he expects the dtor to be run
immediately before the '}' that terminates the scope in which the object
was defined, which is correct. He then indicates that he was surprised
to see the dtor actually executed immediately after a particular
semicolon. He doesn't indicated how he determined that the dtor was
executed, but that's a relatively minor point. The major point is that
the semi-colon he's referring to is immediately followed by the '}' that
he's referring to, so there's no conflict between the expected and
observed timing of the dtor call.
 
> than the end of scope when I would expect, even in debug mode. If it
> were a "release mode" I might understand that this sort of
> optimization, I gather, would take place, but not in debug mode.
 
That depends a lot upon how you define "release mode" and "debug mode", and also upon whether or not the implementation you're using agrees with those definitions. The compiler that I've used most frequently over the past or two performs some annoyingly aggressive optimizations even when invoked with the lowest possible optimization level.

> What's the point of having a dtor if the scope is not respected by the
> compiler?
 
123456789012345678901234567890123456789012345678901234567890123456789012
There's something that's not at all relevant to the code in that
stackoverflow question, but which might be relevant to your code (I
can't tell, because I haven't seen your code). The only thing that
matters, as far as conformance with the C++ standard is concerned, is
whether or not a program produces the same "observable behavior" after optimization as would be permitted before optimization. "observable
behavior" is a piece of jargon defined by the C++ standard in section
4.1.1 - it does NOT mean "behavior which can be observed". It refers to
any type of behavior that falls into one of a listed set of categories.
Any behavior that doesn't fall into one of those categories is not
"observable behavior", no matter how easy it is to observe that
behavior (for instance, by using a debugger).
 
Therefore, if an implementation can produce permitted observable
behavior despite executing the dtor early, than it is permitted to do
so, and that might be precisely what you're seeing.
 
A key point to be aware of: if it matters to you whether or not the dtor
is executed early, there's a pretty good chance that the reason why i
matters to you involves "observable behavior". If so, such
optimizations are NOT permitted. For instance, if you add code before
the end of the scope, inside the dtor itself, and after the end of the
scope which displays information that would allow you to tell what order
those pieces of code occurred in, then it would have to display that
information in that order.
Michael Powell <mwpowellhtx@gmail.com>: Dec 11 07:40AM -0800

Hello,
 
Congrats to the Boost team and Filesystem contributors for this promotion. I haven't worked with it much, YET, but the bit that I have worked with std::filesystem, and boost::filesystem before that, it really does make life working with FS concerns so much easier. Cannot give enough :+1: thumbs ups where that's concerned.
 
Cases in point, I've done extrapolation of absolute, relative, path composition with the "/" operator overload, creating directory(ies), removing files and removing all files/directory(ies) so far. There also appears to be support for Unicode, which is amazing, IMO.
 
Best,
 
Michael Powell
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 11 05:44PM +0100

On 11.12.2018 16:40, Michael Powell wrote:
 
> Congrats to the Boost team and Filesystem contributors for this promotion. I haven't worked with it much, YET, but the bit that I have worked with std::filesystem, and boost::filesystem before that, it really does make life working with FS concerns so much easier. Cannot give enough :+1: thumbs ups where that's concerned.
 
> Cases in point, I've done extrapolation of absolute, relative, path composition with the "/" operator overload, creating directory(ies), removing files and removing all files/directory(ies) so far. There also appears to be support for Unicode, which is amazing, IMO.
 
Yes, it's much better now. :)
 
But.
 
One reason for Boost Filesystem was that the C++03 (and now with
hindsight we know, C++14 and earlier) standard library couldn't handle
non-ASCII filesystem item names in Windows in a portable way.
 
Unfortunately already in its Boost incarnation it partially failed at
that objective, by (1) assuming Windows ANSI encoding as the default for
narrow strings, and by (2) dropping special support for MinGW g++'s lack
of wide string based stream constructors in the 3rd version. And it
appeared there was so much to fight about with this library, that
attention to detail suffered. Hence (IMO) there are some very baffling
and frustrating oversights, e.g. no reliable functionality for finding
the executable's path, which makes it difficult to reliably and portable
access files distributed with the executable.
 
The C++17 standardization of `std::filesystem` is AFAIK the first time
there has appeared text like "for Windows" and "for POSIX" in the C++
standard, but still it was IMO a change in the right direction. The
system specific wording is mainly assurance that the library is
efficient regardless of platform. The standardization got rid of the
proposal's notion of system specific iostream constructors (with wide
string arguments in Windows) by outfitting the iostreams with
constructor overloads that take `std::filesystem::path` arguments.
 
However, the standardization kept the ungood assumption of
configuration-specific and limited Windows ANSI encoding for narrow
text. That means that for modern UTF-8 based code it's VERY easy to
inadvertently invoke the wrong encoding assumption with std::filesystem.
And worse, the `std::filesystem::u8path` function, the only way to
reliably and portably create a path object from an UTF-8 encoded narrow
string, will be deprecated in C++20.
 
Now this on-the-surface-sabotage-like deprecation *may* have something
to do with a proposed distinct UTF-8 narrow character type, and it *may*
have something to do with a vision of a replacement for the current
general encoding conversion support (`codecvt`, deprecated in C++17),
but it looks bad, it looks like a signal that one should forget about
basing code on std::filesystem because it may stop working in 2023.
 
:(
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 11 07:18PM +0100

On 11.12.2018 17:44, Alf P. Steinbach wrote:
> Windows ANSI encoding as the default for narrow strings
 
I meant in Windows. Sorry for hasty typing.
 
Cheers!,
 
- Alf
Tim Rentsch <txr@alumni.caltech.edu>: Dec 11 08:18AM -0800

>> enough to be a competent programmer can easily learn those rules
>> in about 15 minutes.
 
> I'm afraid I'm going to disagree with you.
 
I am interested to explore your response. First a few incidental
comments [I moved the important second paragraph to the end].
 
> I think I am a fairly competent programmer. I'm still working on
> code for embedded devices which ship in the millions, 40 years
> after I first hacked some Fortran together.
 
I take it for granted that you are a competent programmer, based
on your writings in the newsgroup here.
 
> And I feel that writing (a & b) ^ c is clearer than leaving the
> brackets out. It's obvious what is meant, and I don't have to
> think about it.
 
I don't necessarily agree, but that is a separate topic which
I would like to postpone for the moment to help simplify the
discussion.
 
> I don't have the kind of mind that can do rote learning. And it
> is that - there's no logic that says even that multiply takes
> precedence over add. It's just tradition.
 
I didn't mean to imply rote learning. I too am not the sort of
person who does well at learning by rote. I wouldn't have made
the statement unless I thought C's precedence rules carry a
lot of structure that makes them much easier to learn than if
they were random.
 
Your comment about multiply/add suggests you think the choice
was arbitrary. Do you think it was arbitrary? I am skeptical
of that hypothesis.
 
I think any good discussion of this subject should start with
some data rather than just anecdotal evidence. Here is a self
test for associativity and precedence of binary operators
(associativity is always the same operator twice, precedence is
always different operators though they may have the same
"precedence level"). The question in each case is how is the
unparenthesized expression parsed, or in other words where would
the implied parentheses go? Some cases may be syntax errors.
Without consulting any reference (pop quiz!), for what fraction
of the cases does the taker feel confident in their answer?
I hope other people who are interested in this will do the
self-test also. (Yes I have gone through and marked it up
myself.) Needless to say the ordering and handedness of the
examples has been scrambled.
 
 
 
Associativity:
 
a / b / c
a & b & c
a > b > c
a && b && c
a != b != c
a % b % c
a + b + c
a || b || c
a ^ b ^ c
a = b = c
a == b == c
a >> b >> c
a | b | c
a << b << c
a <= b <= c
a >= b >= c
a , b , c
a - b - c
a * b * c
a < b < c
 
 
 
Precedence (two columns):
 
a < b <= c a >> b == c
a ^ b , c a % b ^ c
a - b >> c a % b != c
a >= b % c a >= b || c
a == b || c a ^ b = c
a <= b , c a - b || c
a , b + c a < b | c
a == b > c a + b <= c
a / b % c a - b | c
a && b & c a << b || c
a % b > c a + b ^ c
a > b && c a >= b , c
a || b >> c a << b - c
a * b >= c a , b < c
a || b <= c a + b || c
a >> b = c a % b - c
a % b + c a & b / c
a / b >> c a < b << c
a >> b && c a >= b && c
a > b || c a > b >= c
a / b == c a * b = c
a != b == c a == b = c
a && b - c a == b < c
a > b <= c a + b / c
a && b % c a , b & c
a > b / c a != b - c
a - b * c a = b - c
a * b < c a >= b == c
a && b ^ c a + b == c
a == b % c a * b % c
a / b | c a <= b << c
a * b , c a | b > c
a ^ b & c a & b >> c
a & b || c a - b & c
a - b , c a < b && c
a - b > c a / b >= c
a + b | c a && b <= c
a / b && c a <= b >= c
a ^ b | c a < b >= c
a != b < c a << b / c
a - b / c a >= b != c
a == b , c a << b = c
a = b >= c a & b >= c
a != b * c a * b & c
a > b < c a != b << c
a * b || c a ^ b << c
a << b | c a != b & c
a - b >= c a - b == c
a >> b * c a < b + c
a , b || c a | b == c
a != b || c a != b && c
a && b || c a = b && c
a < b % c a = b != c
a ^ b <= c a <= b | c
a | b >= c a ^ b / c
a << b + c a = b , c
a + b = c a > b * c
a >= b + c a == b * c
a || b < c a >> b != c
a & b <= c a >> b >= c
a >> b | c a <= b = c
a , b && c a << b == c
a | b % c a % b || c
a & b > c a >> b , c
a < b >> c a / b != c
a % b = c a != b > c
a < b & c a + b > c
a ^ b >> c a > b ^ c
a || b = c a >= b ^ c
a , b > c a << b , c
a / b < c a > b << c
a == b <= c a ^ b == c
a % b << c a && b << c
a / b <= c a + b && c
a = b / c a | b * c
a ^ b * c a < b = c
a & b + c a = b | c
a || b ^ c a = b > c
a * b / c a = b & c
a + b * c a / b || c
a == b && c a | b != c
a >> b > c a >> b % c
a || b | c a , b | c
a , b != c a < b ^ c
a % b & c a != b <= c
a + b >> c a >> b << c
a >= b << c a - b < c
a | b & c a - b + c
a != b ^ c a ^ b - c
a - b <= c a * b <= c
a * b && c a , b % c
a & b << c a * b << c
a | b && c a & b == c
a >> b <= c a <= b % c
a != b + c a / b , c
Tim Rentsch <txr@alumni.caltech.edu>: Dec 11 08:35AM -0800

>> out. It's obvious what is meant, and I don't have to think about it.
 
> Or like I mentioned upthread, what's usually clearer with && and || is
> to introduce at least one temporary boolean with a well-chosen name.
 
I agree that it can be better to use a temporary variable (always
suitably named, of course) in such cases. But I wouldn't go so
far as to say "usually". Adding a new variable can make things
worse rather than better in many cases. The question is not so
simple that a single general rule applies.
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: