
Eric Niebler wrote:
Markus Werle wrote:
Summary: I strongly vote against _arg, _left and _right.
I tend to disagree about _arg, _left, and _right. Should I also remove the free functions proto::arg(), proto::left() and proto::right()?
Yes.
It's true, you can use arg_c() for everything, but IMO you have to look closely to see and appreciate the difference between "arg_c<0>(expr)" and "arg_c<1>(expr)", but left(expr) and right(expr) are immediately recognizable and readable. And most C++ operators are binary.
OTOH I really got lost on my first reading due to the aliases everywhere.
2. From a user's point of view I still cannot see the advantage of using argSOME_NUMBER instead of arg_c<SOME_NUMBER>. Couldn't you make arg_c<XX> a first class citizen of namespace proto?
I can't because proto::arg_c already exists, and it's a free function. However, there is proto::_arg_c<>, which is a synonym for transform::arg_c<>. A word about that. Proto reuses names.
I tend to feel uncomfortable about this, but I have no perfect proposal to make it better. _arg_c<> is fine for me.
proto::X is a function, proto::result_of::X is a metafunction that computes the result type of proto::X, proto::functional::X is the function object equivalent of X, and proto::transform::X is the primitive transform equivalent of X. You can't import all these namespaces without making X ambiguous. For the most part, you don't want to, but transforms are different. You very often want to be able to refer to arg_c the function and arg_c the transform in the same bit of code.
I guess that is why I get lost all the time: I read the code in the docs and cannot guess from the name whether this is a typename or a function or whatever and which namespace it belongs. Just a daydream: What happens if it is this way: proto::X is a function, proto::result_of::X_r is a metafunction that computes the result type of proto::X, proto::functional::X_f is the function object equivalent of X, and proto::transform::X_t is the primitive transform equivalent of X. Do we loose anything? Do we run into trouble?
Qualification like "transform::arg_c" is tedious and makes transforms hard to read.
I agree. arc_c_t<1> then? hmm.
That's why the transforms have equivalents in the proto namespace with a leading underscore.
I've always felt this is a little unsavory, but I haven't thought of anything better. I'm open to suggestions.
Let me first try this week to live with proto as it is. It is obvious that proto is the 70th stage of rethinking the same thing over and over again, say: approximately perfect, so probably it is more a matter of getting used to it and how to document it. OTOH I really feel uncomfortable about those identical names in nested namespaces ... I want to rethink this. I once had some mightmare with ADL in a similar context, but I cannot remmeber exactly how it appeared and I am too stupid to invent an example where an abiguity drops in, so probably what I am saying here is FUD only and a matter of taste.
So even if it makes it easier to write the boilerplate parts of proto itself, names based on MACROS are still evil enough to remove them from the _interface_ and for me _argSOME_NUMBER is part of the interface.
Macros? These are not macros, they're typedefs.
I assumed they were generated by a macro until BOOST_PROTO_MAX_ARITY ... I was preaching against that (inexistent?) macro. Now I took a look at proto_fwd.hpp and found they are made by hand and stop at 9. So now I really have a problem: what happens if I need an arity of 120?
So you also feel that typing transform:: over and over is a pain!
OTOH today I always explicitly qualify with the namespace in my own code, using namespace alias if it gets too long ...
Eric, please classify right from the beginning, whether issue #2 takes on "bike shed characteristics" and/or disclose your rationale for _argSOME_NUMBER.
I'm really sorry now about that bike shed comment. :-(
Never mind. It is stored for eternity now, so we can come back to it whenever we want :-P
I may be wrong, but it's possible that after you write some transforms, your opinion on this issue will change. The qualification and the angle brackets really obscure what a transform is doing. Consider the difference between these two:
Use only transform::arg_c<>: struct MakePair : when< function<terminal<make_pair_tag>, terminal<_>, terminal<_> > , make_pair( transform::arg_c<0>(transform::arg_c<1>) , transform::arg_c<0>(transform::arg_c<2>) ) > {};
Use shorter typedefs: struct MakePair : when< function<terminal<make_pair_tag>, terminal<_>, terminal<_> > , make_pair(_arg(_arg1), _arg(_arg2)) > {};
struct MakePair : when< function<terminal<make_pair_tag>, terminal<_>, terminal<_> > , make_pair( _arg_c<0>(_arg_c<1>) , _arg_c<0>(_arg_c<2>) ) > {}; is OK for me, but I understand your intention. Those transforms kill me, but I need them. The advantage of those numbers is: proto is a typelist tool. If you see the index you do not mix it up. With _arg I always have this second, where I translate it back to _arg_c<0>, etc. At least during my approach to the docs those aliases did not help me (but I do not fear nested templates).
They mean the same thing, but the second is a vast improvement, IMO. Proto uses function types to compose primitive transforms. Too many ::'s and <>'s break it up and obscure the meaning.
Yes, templates should use [] instead of <>.
If I get rid of the _argN typedefs, the examples in the documentation will look very imposing.
If those _argN scale up to N=300 or more I will not vote against them. Otherwise if 9 is the maximum, I have a problem with that solution. Markus