Saturday, June 17, 2017

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

"Öö Tiib" <ootiib@hot.ee>: Jun 17 01:17AM -0700

On Friday, 16 June 2017 23:09:01 UTC+3, JiiPee wrote:
> do lobby-kind of things, its only a program running this particular
> simple game. So I was kind of thinking keeping it "simple" rather than
> creating many different classes etc.
 
That was not what mine sentence you quoted said. Lets say you already
have classes for player and game. When player is guaranteed to be always
in game then that for example can make all the checks and handling like
if(player.current_game == NULL) unneeded. That *is* keeping it simpler.
No?
 
> Player structure to be more general. Although that is not difficult to
> do as its a simple game.
 
> I should be thinking ahead even now (even though the game is very simple)?
 
We never know future but it still does not hurt to plan ahead. Otherwise
the changes needed later may be so major that it is better to write new
program instead of making the changes.
Richard Damon <Richard@Damon-Family.org>: Jun 17 05:38PM -0400

On 6/16/17 3:38 PM, JiiPee wrote:
> mean that the game only starts when the first move is done? evertyghing
> before that does not belong to game (like adding player to the
> game/modifying players data etc)?
 
Rolling up 'everything' about something in a single class works in some
cases, but not in others. Particularly when something can get involved
in different contexts. In yoour case I can see the use for several
different classes for differing sorts of information in different
contexts. It sounds like you have possibly one set of information about
a player not connected to any particular game, global information about
them. This information would be saved in permanent storage, and perhaps
updated by specific actions.
 
A second chunk of data is for a player in a particular game. This data
would need to know what player it relates to and what game. This iis
where your current points would be stored and updated as the player
plays the game. This data might only live in the processors ram, or
maybe saved as part of the game if you have that sort of functionality.
 
A last chunk of data would be a historical record. When the game is
over, a summary of how they did is stored in permanent storage, and that
data is likely never changed thereafter.
Jerry Stuckle <jstucklex@attglobal.net>: Jun 16 08:18PM -0400

On 6/16/2017 3:39 PM, Chris Vine wrote:
> in tail position: there is still a destructor to execute. If on the
> other hand it is in tail position, gcc will optimize the function call
> away.
 
No, I don't misunderstand. There is much more involved than just the
optimization level. And you base everything on gcc - which is not the
only compiler - and not always standards-compliant.
 
> that there is "little difference" between tail calls and non-tail calls
> as regards stack usage. With gcc and other modern compilers that is
> wrong.
 
See above.
 
>> still considered recursive.
 
> I prepended the words "in functional programming". You are talking out
> of your ass, not for the first time.
 
Once again you resort to ad hominem attacks instead of the facts. That
shows you cannot refute facts.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 17 02:58AM +0200

On 16-Jun-17 5:42 PM, Tim Rentsch wrote:
> tail call (usually called tail recursion). Often such function
> bodies will be optimized during compilation so recursive calls
> are turned into loops rather than calls.
 
Good teaching point.
 
For C++ it's important to note that if there are local variables with
destructors, whose destructors run after the recursive call, then the
term "tail-recursive" doesn't really apply, and the optimization can be
foiled. I.e. one should not write code as if this optimization were an
effectively guaranteed feature. In fact it's worse: at least some
earlier version of Visual C++ failed to optimize the usual tail
recursive factorial function beginner's example, when the return type
was floating point (it optimized that tail recursion fine for `int`).
 
 
> reverse( List &s ){
> s = reverse_onto( s, 0 );
> }
 
[snipped a part that did not include discussion of how this works]
 
 
> Using tail recursion has given us a nice compact loop to effect
> list reversal.
 
At the cost of clarity.
 
 
> Do you understand how the list reversal functions shown
> above work, or is more explanation needed?
 
Can't say I did at first glance, so I am not at all sure that it helped
the OP with the question of understanding. Though it probably helped in
other ways, including teaching that tail recursion can often be optimized.
 
At first this looked to me like something from a an obfuscated code
contest, apparently intentionally using common obfuscation techniques:
 
• uninformative single letter names,
 
• inconsistent naming conventions (`List` versus `list_node`),
 
• the perplexing and apparently misleading name `reverse_onto` (which
however does make some sense /after/ figuring out how this works),
 
• expression with side effects, and
 
• a recursive call, indirection, in there, with apparent
switching/change of meaning of arguments in each call.
 
Instead I think it's good to teach beginners that
 
• source code is about communicating to humans, not so much about
communicating to a compiler.
 
And therefore to use /self-describing names/, except where there is
nothing easy to describe or where there is a strongly established
convention such as `T` or `i`.
 
And also, consistent with that principle, I think it's good to teach
beginners that
 
• programming is not a contest in brevity and terseness.
 
And therefore to not at all be afraid of producing many lines of code,
but rather to embrace that eagerly where it improves clarity. But of
course, to not do it needlessly. Being able to fit much of the relevant
code for something in one screen-full, is helpful in actual work.
 
And third, also consistent with the first principle, that
 
• comments can/should be used for non-obvious things.
 
I rewrote the code according to the above principles:
 
 
------------------------------------------------------------------
using List = struct Node*;
 
struct Node
{
int value; // Having this first supports curly braces init.
List next;
};
 
namespace impl {
 
auto reversed(
List const s, // A valid list
Node* const node_originally_before_s // Start of a rev list
)
-> List
{
if( s == nullptr )
{
return node_originally_before_s;
}
 
List const rest_of_the_list = s->next;
s->next = node_originally_before_s;
return reversed( rest_of_the_list, s );
}
 
} // namespace impl
 
void reverse( List& s )
{
s = impl::reversed( s, 0 );
}
------------------------------------------------------------------
 
With self-describing names, consistent naming conventions, unambiguous
function name, and no side-effect expressions, the recursive call with
the apparent switch/change of arguments should be easier to understand.
 
However, as the English say, the proof is in the pudding.
 
 
- Alf
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 17 09:27AM +0100

On Fri, 16 Jun 2017 20:18:53 -0400
Jerry Stuckle <jstucklex@attglobal.net> wrote:
[snip]
> Once again you resort to ad hominem attacks instead of the facts.
> That shows you cannot refute facts.
 
The facts are that:
 
* In response to a poster who said "it's important to write such
functions so any recursive call is a tail call", you said "Whether it
is head, middle or tail recursion makes little difference in the
amount of memory consumed",
 
* That poster was right and you were wrong. Whatever obfuscation you
may try to introduce now, as I pointed out the key to the issue with
gcc and clang is to avoid having objects in function scope with
non-trivial destructors, in order to keep the recursive calls as tail
calls.
guinness.tony@gmail.com: Jun 17 02:11AM -0700

On Saturday, 17 June 2017 01:59:05 UTC+1, Alf P. Steinbach wrote:
 
<snip>
 
> However, as the English say, the proof is in the pudding.
 
No, we don't. We say "the proof of the pudding is in the eating."
 
The mangled (and unintelligible) version you quoted probably
originated on the other side of the Atlantic.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 17 12:53PM +0200


> No, we don't. We say "the proof of the pudding is in the eating."
 
> The mangled (and unintelligible) version you quoted probably
> originated on the other side of the Atlantic.
 
Thanks! Learned something… :)
 
From <url: https://en.wiktionary.org/wiki/the_proof_is_in_the_pudding
>, essentially what you wrote:
 
"Etymology: This phrase is a shortened form of the proof of the pudding
is in the eating (14th century). The shorter version dates back to the
1920s and came into common use in the United States in the 1950s."
 
 
Cheers!,
 
- Alf
Jerry Stuckle <jstucklex@attglobal.net>: Jun 17 05:33PM -0400

On 6/17/2017 4:27 AM, Chris Vine wrote:
> gcc and clang is to avoid having objects in function scope with
> non-trivial destructors, in order to keep the recursive calls as tail
> calls.
 
Nope. You went on to qualify IF there isn't an object with a
non-trivial destructor... IF the function call is in the tail
position... IF you use gcc ... IF you use -O2 or -O3 THEN gcc MIGHT make
this a iterative call.
 
One can always make special cases. However, the general case is not
true. Any change in the above and it won't be iterative. Counting on
it being an iterative operation is an invitation to bugs when
maintenance changes those conditions and the call is no longer iterative.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
woodbrian77@gmail.com: Jun 16 06:58PM -0700

On Monday, May 29, 2017 at 12:23:35 PM UTC-5, Jorgen Grahn wrote:
> only way to avoid broken builds. And you lose most of the benefits of
> using Make, compared to using e.g. a straight shell script. --- But
> if it works for you, I cannot object.
 
With a new version of g++ and my efforts, a clean build now takes
less than 4 seconds on that same machine.
 
Now I'm trying to figure out a travis.yml file that would be helpful.
 
 
Brian
Ebenezer-group - The Name of The L-RD is a strong tower. The
righteous runs into it and is safe. Proverbs 18:10
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: