Re: [boost] Re: Pretty Good Initialization Library

In-Reply-To: <cch4as$941$1@sea.gmane.org> andrewalex@hotmail.com (Andrei Alexandrescu \(See Website for Email\)) wrote (abridged):
I was worried more (only) about the order of evaluation.
v += foo(), bar();
I don't think order of evaluation is sacred. However, I am also not keen on using comma for this. I'd rather use operator<<(). v << foo() << bar(); This is partly because comma is so small its easy to overlook, partly because it is used for so many other common things, and partly because I think the semantics of operator<<() fit better here. "Append these items to that stream or container, with conversion or formatting if appropriate." I would also be happy with: v << repeat(5) << 4; meaning: v << 4 << 4 << 4 << 4 << 4; and so forth. It doesn't bother me that: v = 1, 2, 3; has no direct equivalent. It becomes: v.clear(); v << 1 << 2 << 3; Presumably you'd be content with operator<<() in that it doesn't imply an order of evaluation. -- Dave Harris, Nottingham, UK

From: brangdon@cix.compulink.co.uk (Dave Harris)
In-Reply-To: <cch4as$941$1@sea.gmane.org> andrewalex@hotmail.com (Andrei Alexandrescu \(See Website for Email\)) wrote (abridged):
I was worried more (only) about the order of evaluation.
v += foo(), bar();
Unless I'm mistaken, there is but one sequence point in such an expression, regardless of whether you overload operator,. Thus, any expression using commas must be understood to have indeterminant order of evaluation. Consider: int v[] = { foo(), bar() }; Doesn't this exhibit the same problem? If so, the problem is only that an initialization library exposes the problem to more daylight.
I don't think order of evaluation is sacred. However, I am also not keen on using comma for this. I'd rather use operator<<().
v << foo() << bar();
This is partly because comma is so small its easy to overlook, partly because it is used for so many other common things, and partly because I think the semantics of operator<<() fit better here. "Append these items to that stream or container, with conversion or formatting if appropriate."
I don't like that. It suggests formatted insertion rather than initialization. As you point out, conversion is possible, but one can't overload operator<< to customize the initialization. Thus, it doesn't fit neatly with IOStreams. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
[...] Thus, any expression using commas must be understood to have indeterminant order of evaluation.
Are you sure?
Consider:
int v[] = { foo(), bar() };
Doesn't this exhibit the same problem? If so, the problem is only that an initialization library exposes the problem to more daylight. [...]
But consider: int v = foo(), bar(); I agree that expecting more order-of-initialization than you get is a problem, but the funny thing is that the comma operator gives you more than other uses of the comma. Dave

From: "David B. Held" <dheld@codelogicconsulting.com>
Rob Stewart wrote:
[...] Thus, any expression using commas must be understood to have indeterminant order of evaluation.
Are you sure?
No, I was wrong. The built-in semantics are well-defined for some uses.
Consider:
int v[] = { foo(), bar() };
Doesn't this exhibit the same problem? If so, the problem is only that an initialization library exposes the problem to more daylight.
This doesn't exhibit the same behavior because of 1.9/18, contrary to my questioning above.
But consider:
int v = foo(), bar();
I agree that expecting more order-of-initialization than you get is a problem, but the funny thing is that the comma operator gives you more than other uses of the comma.
Yes, overloading operator, eliminates the built-in comma's "internal" sequence point, so it can be surprising. This, of course, is Andrei's original point. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

"Rob Stewart" <stewart@sig.com> wrote in message news:200407072103.i67L3Jk28273@tesh.systems.susq.com...
From: brangdon@cix.compulink.co.uk (Dave Harris)
In-Reply-To: <cch4as$941$1@sea.gmane.org> andrewalex@hotmail.com (Andrei Alexandrescu \(See Website for Email\)) wrote (abridged):
I was worried more (only) about the order of evaluation.
v += foo(), bar();
Unless I'm mistaken, there is but one sequence point in such an expression, regardless of whether you overload operator,. Thus, any expression using commas must be understood to have indeterminant order of evaluation.
It is exactly such false sense of security and such misunderstandings that makes me highly suspicious of overloading the comma operator. Worse, comments come that have an apparence of legitimacy. Unless I am even more mistaken, your statement above is false. If that's the case, hey, confusion is among the inner circle... how about the casual users?
Consider:
int v[] = { foo(), bar() };
Doesn't this exhibit the same problem?
No. Andrei

From: "Andrei Alexandrescu \(See Website for Email\)" <andrewalex@hotmail.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200407072103.i67L3Jk28273@tesh.systems.susq.com...
From: brangdon@cix.compulink.co.uk (Dave Harris)
In-Reply-To: <cch4as$941$1@sea.gmane.org> andrewalex@hotmail.com (Andrei Alexandrescu \(See Website for Email\)) wrote (abridged):
I was worried more (only) about the order of evaluation.
v += foo(), bar();
Unless I'm mistaken, there is but one sequence point in such an expression, regardless of whether you overload operator,. Thus, any expression using commas must be understood to have indeterminant order of evaluation.
It is exactly such false sense of security and such misunderstandings that makes me highly suspicious of overloading the comma operator. Worse, comments come that have an apparence of legitimacy. Unless I am even more mistaken, your statement above is false. If that's the case, hey, confusion is among the inner circle... how about the casual users?
If operator, is overloaded, then there is only one sequence point in the above expression. If not, then there are two. I forgot about 1.9/18.
Consider:
int v[] = { foo(), bar() };
Doesn't this exhibit the same problem?
No.
You're right. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
"Dave Harris" <brangdon@cix.compulink.co.uk> wrote
In-Reply-To: <cch4as$941$1@sea.gmane.org>
has no direct equivalent. It becomes: v.clear(); v << 1 << 2 << 3;
or v <<= 1 << 2 << 3;
Oops ... maybe Not ! regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"Dave Harris" <brangdon@cix.compulink.co.uk> wrote
In-Reply-To: <cch4as$941$1@sea.gmane.org>
has no direct equivalent. It becomes: v.clear(); v << 1 << 2 << 3;
or v <<= 1 << 2 << 3;
surely not ;-) *maybe* it would be (v <<= 1) << 2 << 3 -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"Dave Harris" <brangdon@cix.compulink.co.uk> wrote
In-Reply-To: <cch4as$941$1@sea.gmane.org>
has no direct equivalent. It becomes: v.clear(); v << 1 << 2 << 3;
or v <<= 1 << 2 << 3;
surely not ;-)
*maybe* it would be
(v <<= 1) << 2 << 3
Or maybe we should just use int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) ); as I've been doing for years.

"Peter Dimov" <pdimov@mmltd.net> writes:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
Looks good to me. In what way does Thorsten's library improve on this idiom? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams <dave <at> boost-consulting.com> writes:
"Peter Dimov" <pdimov <at> mmltd.net> writes:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
Looks good to me. In what way does Thorsten's library improve on this idiom?
well, you can initialize too. And for maps, you can use (key,value) lists. And you can say you're having a list of X and want to construct them with n arguments using (arg1,arg2,...,argn) syntax. Please see the docs in the cvs in libs/assign/index.html br Thorsten

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:013e01c464e5$980fd7c0$0600a8c0@pdimov...
David Abrahams wrote:
"Andy Little" <andy@servocomm.freeserve.co.uk> writes:
"Dave Harris" <brangdon@cix.compulink.co.uk> wrote
In-Reply-To: <cch4as$941$1@sea.gmane.org>
has no direct equivalent. It becomes: v.clear(); v << 1 << 2 << 3;
or v <<= 1 << 2 << 3;
surely not ;-)
*maybe* it would be
(v <<= 1) << 2 << 3
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
What??? No 'static' in front of cv??? :o) Now seriously, 'static' can improve performance, and 'const' wouldn't hurt, either. Andrei

Andrei Alexandrescu (See Website for Email) wrote:
"Peter Dimov" <pdimov@mmltd.net> wrote in message news:013e01c464e5$980fd7c0$0600a8c0@pdimov...
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
What??? No 'static' in front of cv??? :o)
Now seriously, 'static' can improve performance, ...
For three elements??? ;-)

Russell Hind wrote:
Peter Dimov wrote:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
is 'end' in boost?
No, but I find template<class T, int N> T * end( T (&a) [N] ) { return a + N; } and #include <boost/utility/end.hpp> almost equally easy to type.

Russell Hind wrote:
Peter Dimov wrote:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
is 'end' in boost?
I think the recently accepted container traits library has it. - Volodya

"Vladimir Prus" <ghost@cs.msu.su> wrote in message news:ccm43l$q1d$1@sea.gmane.org...
Russell Hind wrote:
Peter Dimov wrote:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
is 'end' in boost?
I think the recently accepted container traits library has it.
That's cool. Then, what is the motivation of the initialization library? Andrei the malicious one

On Fri, 9 Jul 2004 09:12:53 -0700, "Andrei Alexandrescu (See Website for Email)" <andrewalex@hotmail.com> wrote:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
That's cool. Then, what is the motivation of the initialization library?
in my experience i have to initialize STL containers only in extremely rare cases, so i don't need an initialization library, but if something allows me to write it in a way that resembles initialization i still want it -- because it's cool :O) my two cents on the operator debate: - people who know that "," is a sequence point will not get bitten by it, as they also tend to know that an overloaded "," is not a sequence point; and if they do get bitten, they deserve it -- library authors should know better, application developers intentionally relying on evaluation order are evil - people who don't know what a sequence point is theoretically will get bitten regardless of which operator is used here, and practically will not get bitten, not more frequently than in any other part of their code with any other operator (built-in or user-defined) imho the coding guideline was never valid, and operator "," is the best choice here br, andras

Andrei Alexandrescu (See Website for Email <andrewalex <at> hotmail.com> writes:
"Vladimir Prus" <ghost <at> cs.msu.su> wrote in message news:ccm43l$q1d$1 <at> sea.gmane.org...
Russell Hind wrote:
is 'end' in boost?
I think the recently accepted container traits library has it.
indeed. See <boost/range/end.hpp> in the main cvs.
That's cool. Then, what is the motivation of the initialization library?
Andrei the malicious one
1. initilization. 2. easy syntax with pairs for maps 3. easy syntax n-tuples of arguments 4. you can also choose to call eg. push_front instead of push_back if the container allows it 5. a few hooks like vector<int> v; v += 1,repeat(5,1); // do 5 1's br Thorsten

Vladimir Prus wrote:
Peter Dimov wrote:
Or maybe we should just use
int cv[] = { 1, 2, 3 }; v.assign( cv, end(cv) );
as I've been doing for years.
That's nice! Do you have an equally simple recipe for std::map initialization?
For maps, I find the sequence of m[ k ] = v; good enough for my needs. A static array of pairs has about the same overhead per line: { k, v }, and dropping this down to just k, v, never seemed critical, considering the low frequency of single-place-hardcoded-init maps.

Peter Dimov wrote:
That's nice! Do you have an equally simple recipe for std::map initialization?
For maps, I find the sequence of
m[ k ] = v;
good enough for my needs. A static array of pairs has about the same overhead per line:
{ k, v },
and dropping this down to just
k, v,
never seemed critical, considering the low frequency of single-place-hardcoded-init maps.
Ok, I understand. I'm writing at the moment code like: ....... (*casts)[make_pair(Type::FloatTy, Type::DoubleTy)] = NM::FTOD; and I think I'd rather like to eliminate that (*casts) part, and make_pair, but while assign library can eliminate (*casts), I'm not sure it can do much about 'make_pair'. Or it can....? - Volodya

Vladimir Prus wrote:
Ok, I understand. I'm writing at the moment code like: ....... (*casts)[make_pair(Type::FloatTy, Type::DoubleTy)] = NM::FTOD;
and I think I'd rather like to eliminate that (*casts) part, and make_pair, but while assign library can eliminate (*casts), I'm not sure it can do much about 'make_pair'. Or it can....?
static void add_cast( Type x, Type y, NM nm ) { (*casts)[ make_pair(x, y) ] = nm; } ?

Peter Dimov wrote:
Vladimir Prus wrote:
Ok, I understand. I'm writing at the moment code like: ....... (*casts)[make_pair(Type::FloatTy, Type::DoubleTy)] = NM::FTOD;
and I think I'd rather like to eliminate that (*casts) part, and make_pair, but while assign library can eliminate (*casts), I'm not sure it can do much about 'make_pair'. Or it can....?
static void add_cast( Type x, Type y, NM nm ) { (*casts)[ make_pair(x, y) ] = nm; }
?
That surely will work, but if I have a way to write init(map) = Type::FloatTy, Type::DoubleTy, NM::FTOD, ...................... I'd sure use it. But until it's possible, 'add_cast' or even macros will do for me. - Volodya

Vladimir Prus <ghost <at> cs.msu.su> writes:
Ok, I understand. I'm writing at the moment code like: ....... (*casts)[make_pair(Type::FloatTy, Type::DoubleTy)] = NM::FTOD;
and I think I'd rather like to eliminate that (*casts) part, and make_pair, but while assign library can eliminate (*casts), I'm not sure it can do much about 'make_pair'. Or it can....?
Hm...it can't totally figure out you code, but surely you don't need make-pair or anything. Any list of arguments can be forwarded to a call to the constructor of the type you're dealing with. Please see the docs in /libs/assign/ br Thorsten

Thorsten Ottosen wrote:
Vladimir Prus <ghost <at> cs.msu.su> writes:
Ok, I understand. I'm writing at the moment code like: ....... (*casts)[make_pair(Type::FloatTy, Type::DoubleTy)] = NM::FTOD;
and I think I'd rather like to eliminate that (*casts) part, and make_pair, but while assign library can eliminate (*casts), I'm not sure it can do much about 'make_pair'. Or it can....?
Hm...it can't totally figure out you code, but surely you don't need make-pair or anything. Any list of arguments can be forwarded to a call to the constructor of the type you're dealing with.
Please see the docs in /libs/assign/
Hmm.. maybe you can give me more hints? While: vector<pair<int, int> > v; push_back(v)(1, 2); works, map<pair<int, int>,int> months; insert(months) (1, 2, 3); does not, and map<pair<int, int>,int> months; ( list_of(1, 2), 31 ) does not work either. - Volodya

Vladimir Prus <ghost <at> cs.msu.su> writes:
Hmm.. maybe you can give me more hints? While:
vector<pair<int, int> > v; push_back(v)(1, 2);
works,
map<pair<int, int>,int> months; insert(months) (1, 2, 3);
does not, and
yeah, that would be magical :-) I not sure such a syntax would be good.
map<pair<int, int>,int> months; ( list_of(1, 2), 31 )
does not work either.
something along these lines would be good. I think insert( months )( map_list_of(1,2), 31 ); should work (because it is list_of<pair<T,U> >). Alternatively, you would need to specify that you are using pair<int,int> explicitly or use a typedef: typedef pair<int,int> key_t; insert( months )( key_t(1,2), 31 ); You have surely found something that could be better, ie, how can we deduce what list_of should store?. I think it is impossible to do something like that. br Thorsten
participants (11)
-
Andras Erdei
-
Andrei Alexandrescu (See Website for Email)
-
Andy Little
-
brangdon@cix.compulink.co.uk
-
David Abrahams
-
David B. Held
-
Peter Dimov
-
Rob Stewart
-
Russell Hind
-
Thorsten Ottosen
-
Vladimir Prus