Wednesday, 27 July 2016

Structure-like std::tuple usage


While reading P0095R0, WG21* I stumbled upon a cool trick. If you define following structures:
  struct x { double value; };
  struct y { double value; };
  struct z { double value; };

  using point = std::tuple<x, y, z>
you will then be able to write:
  auto x = std::get<x>(point);
  auto y = std::get<y>(point);  
  auto z = std::get<z>(point); 
Look at that! Now we can use std::get<x> to fetch the 'x' value of the tuple, std::get<y> for 'y' and so on, instead of plain, old (and ugly...):
  using point = std::tuple<double, double, double>

  auto x = std::get<0>(point);
  auto y = std::get<1>(point);  
  auto z = std::get<2>(point);
Cool, isn't it?

But the author dismisses such tricks on the spot:
"Should we use this approach everywhere and deprecate the use of struct in any context? In the author's opinion we should not. The use of wrapper types is much more complicated to both read and understand than a plain struct. For example, the wrapper types that were introduced, such as the 'x' type, make little sense outside of their corresponding tuples, yet they are peers to it in scope. Also, the heavy syntax makes it difficult to understand exactly what is intended by this code."
...on the premise that it is too clever. Come on, that little bit of extra code in one place, and then this readability all over your source code? But wait, it comes even harder:
"While the utility of type selection and SFINE for visitors is quite clear for advanced C++ developers, it presents significant hurdles for the beginning or even intermediate developer. This is especially true when it is considered that the visit function is the only way to guarantee a compilation error when all cases are not considered."
That got me thinking. First I wanted to dismiss the argument along the lines of: "what, how can a C++ developer not know what SFINAE is...", but then another thought grew stronger and stronger: "come down from the expert-only, high-church, pure-blood stance, C++ should be usable for beginners too!". Just think about yourself trying to learn an new programming language for a minute. Do you want it esoteric and complicated? Not really. So this is really a show stopper, kind of...

Because, we don't want to give up our freshly discovered syntactic candy so easily, do we?

Thus, I think we need a new syntax extension for C++17 (or C++0y?)**:
  using point = std::tuple<x : double, y : double, z : double>

  auto x = std::get<x>(point);
  auto y = std::get<y>(point);  
  auto z = std::get<z>(point);
Nowadays everybody gets his/hers pet feature added to C++17 (just look at if and switch initializers), so why not?

Come on guys! Who's with me? 


--
* "The Case for a Language Based Variant", C++ Standard proposal P0095R0. It discusses advantages of language based variant implementation vs. a library-only solution.

** of course we could use the brand-new destructuring like in:
  using point = std::tuple<double, double, double>

  auto [x, y, z] = point;
but that's not what we want. We need named access to single elements of the tuple. And don't say we shouldn't use tuple, because we simply want to!

2 comments:

Derek Ross said...

I'm with you! Luckily it looks like they're going to some tuple-like capabilities for regulars structs... hallelula! See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4175.pdf

Marek Krj said...

Hey, that's nice! Default, compiler-generated comparison operators for structs... (and the reported conversation with Dennis Ritchie as a bonus!)