Multiple responses to the discussion below; figured that might be less
noisome than replying four separate times in a row.
On Sat, Jun 1, 2013 at 6:06 AM, Nicol Bolas <
jmck...@gmail.com> wrote:
>
>
> Some would say that it's superior due to the shorter, more readable syntax for creating and using tuples. Granted, that wouldn't be me, because shorter, more readable syntax makes people use these things far more often than they should.
Encourage good coding habits by inflicting hardship? How delightfully
medieval. :)
I do agree with the idea of making it easier to do the right thing
rather than the wrong thing since most people just take the path of
least resistance whenever possible. However, I'd argue that
syntactical tuples being "too easy" in some circumstance is really
just a symptom of the more appropriate option (say, a struct with
well-named members) being too hard. For example, it might be handy if
one could define a struct while declaring a function rather than
needing to split the declarations up.
Compare the follow syntactical tuples + easy anonymous structs:
auto get_tuple() -> { int; float; }
auto get_struct() -> { int index; float value; };
with having neither:
auto get_tuple() -> std::tuple<int, float>
struct something_t { int index; float value; };
auto get_struct() -> something_t;
In the latter case, it's a lot easier to use tuples, but in the
former, there's hardly any real difference. It's not so much about
making tuples hard to use but rather making the struct version so easy
to use that - where those member identifiers are actually useful -
there's little reason to prefer the tuple version even if you're
really lazy.
The anonymous struct would make sense only in some cases of course,
but maybe it fills a gap between tuples and named structs that is
missing? My fear, mirroring probably your own, would be that novice
coders would use the anonymous struct version more often than they
should; even then, it is at least better than using the existing
std::tuple version, yes?
> I would much rather see reflection capabilities that make tuples entirely obsolete. Why make a tuple when you can query a struct's members by index? Why make a tuple if you can generate new types via template metaprogramming?
Without something like the above, the reason would be code locality.
Same reason lambdas are so popular over functors. It's much easier
both to write _and_ read/review/maintain code if you don't have to
split up closely-related data definitions and code flow into multiple
places.
Also, maybe sometimes the mandatory member identifiers of structs
would just be noise as there's no strong need or obvious choice for
them. If you're always querying struct members by index and hence
don't even need them, why be forced to try to choose any when making
the type? When meta-programming it'd be even harder to pick decent
identifiers, I think, and in many cases I'd bet you'd just be writing
code to spit out names like "member1, member2" and so on.
On Sat, Jun 1, 2013 at 1:47 AM, Nikolay Ivchenkov
<
mk.ivc...@gmail.com> wrote:
>> I'm hesitant to suggest ...[] only out of consistency; it's the operator for accessing containers of homogeneous types, and typically some kind of template accessor is used elsewhere.
>
> ...[] and [] are different operators, as well as sizeof...() and sizeof/sizeof() are different operators (with different semantics).
True enough. You're right. I don't personally care for the existing
syntax examples much either but that ship has sailed.
I am a fan of aiming for reusable syntax rather than one-off special
cases, though. It's easy to think up new syntax for specific uses but
there's whole classes of cool (and now common) C++ tricks that fell
out "accidentally" from generic language designs. Meta-programming in
itself is kind of an accident originally, as I understand. Aiming for
user-overloadable operators on parameter packs with constexpr
overloads, as an example, would allow a library addition like the
following and maybe all kinds of other cool future good ideas that we
haven't even thought of yet:
template <typename ...Args>
auto operator[](Args... args, constexpr size_t index) -> typename
std::type_at<index, Args...>::type&&
{
return std::value_at<index>(args...);
}
If one is going to go the route of proposing (possibly quite complex)
core-language features, I'd aim for more generic ones. Even if they
do lead to less experienced coders doing what Nicol Bolas fears and
writing crappy code, that is going to happen anyway (inexperienced
coders even in "simple" languages like Lua or LISP write absolutely
awful code until they get a solid grasp of the proper idioms and
practices of their chosen profession/tool). The extensible solution
could be abused for evil by the inexperienced, but it could also be
used for good by the knowledgeable, or at truly worst only reasonable
useful for the one-off solution same as the one-off language addition
would be. The generic solution facilitates better libraries and many
ideas that can evolve over time rather than entrenching a single idea
forever. Unless the one-off solution is really easier to implement
than the generic one, there's no extra cost to the generic solution
but a lot of potential gain.
Hence why I'd rather provide a library solution for this particular
problem now which could then be used as building blocks for future
library additions using language additions like the example above.
Not really up to me, though, of course. :)
On Fri, May 31, 2013 at 3:21 AM, <
corn...@google.com> wrote:
> I think we want std::value_at<I>(args...) as well, to pick one value from a
> variadic function argument pack. But yes, we definitely need this.
Seems sensible.
I'd be a fan of just making an overload for std::get since that
doesn't immediately look like a tuple-only facility and hence seems
"obvious." Unfortunately, I can't think of a way to resolve the
ambiguity for a type list comprised of a single std::tuple.
std::get<0>(args...) would expand to something like
std::get<0>(some_tuple) and then return the first value in the tuple
rather than the whole tuple itself as would probably be desired.
I can't think of any way to design a new std::get
overload/specialization that wouldn't have that problem; maybe someone
else can.
-
In any case, I might take a stab and writing some proposal-ese for the
template-only version of what I originally put up (plus the template
alias versions plus a version of std::value_at). If I do I'd need a
sponsor/advocate for the paper as I am not a committee member and I am
not feasibly able to make it to the vast majority of committee
meetings.
On the original-idea side of the discussion, I'm not super fond of the
name type_at, especially not the alias version which would be
type_at_t for consistency with the other aliased traits; any other
suggestions? For consistency with tuple's tuple_element the only
other thing I can think of is something like variadic_element but I'm
not really digging that at all.
-Sean