c++now 2017 trip report - part 2/2

29 may 2017

This is the second and final part of my C++Now 2017 trip report. You can find the first part here: "c++now 2017 trip report - part 1/2".

thursday, may 18

  • Call: A Library that Will Change the Way You Think about Function Invocations (by Matt Calabreses)

    When reading WG21's latest mailing list back in May 2016 in surprised by a very interesting proposal by Matt Calabrse: "A Single Generalization of std::invoke, std::apply, and std::visit" (P0376).

    The mentioned standard facilities may quite unrelated at first:

    • std::invoke homogenizes function and member function invocation. (...and it's unfortunately still not constexpr...)

    • std::apply, given a tuple, invokes a Callable object by unpacking the tuple as the arguments.

    • std::visit, given some variants, invokes an overload set with the currently active variant alternatives.

    Matt's proposed generalization was, in my opinion, brilliant. Instead of having multiple facilities that deal with "particular expansions" (e.g. tuple items and variant alternatives) in function invocations, there will one generic and flexibile facility: std::call.

    The "particular expansions" I just mentioned are handled by "argument providers", which basically are powerful placeholders that will be expanded in place when performing the invokation. An example is worth a thousand words:

    auto print = [](const auto&... xs)
    {
        (std::cout << ... << xs);
    };
    
    std::call(print, 0, 1, 2, 'a');
    // Prints "012a".
    
    auto args = std::make_tuple(0, 1, 2, 'a');
    std::call(print, std::unpack(args));
    // Prints "012a".

    In the code snippet above, std::unpack is a placeholder that is recognized by std::call and expands the passed tuple in place when invoking print. Its flexibility becomes evident when mixing normal argument with tuples:

    auto args = std::make_tuple(1, 2);
    std::call(print, 0, std::unpack(args), 'a');
    // Prints "012a".

    Replicating the above example with std::apply and lambdas would require a lot of boilerplate, especially if noexcept and SFINAE friendliness are required.

    std::unpack is only one of various useful "argument providers" that Matt proposed:

    • active_field_of, which resolves to the currently active alternative of a variant. Example:

      std::variant<int, char> v{'a'};
      std::call(print, std::active_field_of(v))
      // Prints "a".
    • to_constant_in_range<T, Min, Max>, which provides a run-time to compile-time bridge. It converts a run-time value between Min and Max to the corresponding std::integral_constant. This is implemented by generating a constexpr table of function pointers, similarly to variant visitation.

    All of the "argument providers" are fully composable and users can write their own.

    Matt presented an updated version of the library at his two C++Now sessions, formally covering the ArgumentProvider concept and guiding the audience through the design of the library and the implementation details.

    The presentation was very enjoyable and interactive. Matt claimed that he feels that the functionality provided by call should be part of the language, and I agree with him - it would be invaluable to have a powerful and extensible language feature that allowed "argument providers" to be resolved in any function call.

    This is a must watch talk!

  • Implementing variant visitation using lambdas (by Vittorio Romeo)

    My talk was a tutorial on how to implement overload-based pattern-matching visitation syntax for variants. The idea is to have the user provide a bunch of lambdas that can handle all variant alternatives and overload them on the spot. The final result looks like this:

    • Non-recursive variants:

      std::variant<circle, box> v0{/* ... */};
      std::variant<circle, box> v1{/* ... */};
      
      match(v0, v1)([](circle, circle){ /* ... */ },
                    [](circle, box)   { /* ... */ },
                    [](box,    circle){ /* ... */ },
                    [](box,    box)   { /* ... */ });
    • Recursive variants:

      match_recursively<int>(some_expression)(
          [](auto, number x) { return x; },
          [](auto recurse, const std::unique_ptr<r_expr>& x)
          {
              const auto& [lhs, op, rhs] = *x;
              return match(op)(
                  [&](plus) { return lhs + recurse(rhs); },
                  [&](minus){ return lhs - recurse(rhs); });
          });

    You can already watch the ACCU 2017 version here on YouTube, although the version I gave at C++Now contained some extra content on how painful it is to deduce the arity of generic lambdas and how hard it is to create an elegant unified syntax for recursive/non-recursive visitation.

    I'm also currently working on a library that provides polished versions of the visitation facilities I covered in my talk, plus some extra ADT goodies: scelta. It's "zero-overhead syntactic sugar" for both variant and optional types, that works with any common implementation, not just std::variant.

friday, may 19

  • Competitive Advantage with D (by Ali Çehreli)

    I admit that I've always been interested in D ever since its release, but I've always been put off by some factors:

    • Reference types: in D, structs have value semantics and classes have reference semantics, like C#. I really hate this distinction as I want full control on how I decide to work with my types.

    • Built-in garbage collection: sure, it can be disabled, but then you cannot use fundamental language features such as closures or exceptions.

    • Attitude towards other programming languages: I've noticed an exaggerate cocky attitude multiple times - this is probably just Andrei trying to draw attention to the language being provocatory but I find it really annoying.

    tweet #0

    tweet #0

    tweet #1

    tweet #1

    D however has incredible features that make it really attractive:

    • Powerful metaprogramming: in D you can have a static if that conditionally compiles things depending on a constant expression. Sounds like if constexpr, right? Well, static if can be placed pretty much everywhere - as an example, it can be used to conditionally compile struct data members or member functions!

      struct foo
      {
          static if(bar())
          {
              double x;
          }
          else
          {
              float x;
          }
      };

      You can also evaluate any function at compile-time, write a D function that produces a D source code string and mix the string inside the main program during compilation as part of the original source code.

      auto example(string x)
      {
          return "int " ~ x ~ ";";
      }
      
      void main()
      {
          mixin(example("foo"));
          foo = 100;
      }

      Strings and token sequences can be passed as template arguments and trivially parsed/processed with normal D code. Ben and Jason have shown the C++Now audience how crazy it is to implement JSON literals in C++17... well, it would be quite easy in D!

    • UFCS (Uniform Function Call Syntax): free functions can be called with member function syntax. This feature makes algorithm chaining easy and elegant. Here's a code snippet that prints all even numbers to stdout:

      100.iota.filter!(x => x % 2 == 0).writeln();
    • Contracts, built-in unit testing, a package manager, and many more...

    I'm really happy to say that the interesting keynote and friendliness of Ali made me truly excited to play around with D - after the presentation we sat together for a few hours trying to reimplement unique_ptr in D and looking at the generated assembly. It was a lot of fun and a great learning experience for me. He also gave me a copy of his Programming in D which I highly recommend if you're interested in the language.

    I'm currently playing around with it and even started proposing a syntax for @nogc closures. I find D very promising but I really want to see the GC become truly optional (i.e. no language features require it).

  • No raw std::thread! - Live Tweet Analysis in C++ (by Kirk Shoop)

    This presentation showed the design and implementation behind a "live tweet analysis" application that processed incoming tweet data in a completely asynchronous manner though the use of "Reactive Extensions for C++".

    Reactive Extensions are kind of a "generalization of futures": they deal with streams of asynchronous data (compared to a single datum), are highly composable, and avoid callback hell. You can think of them as "ranges" for values distributed in time rather than distributed in space. I found this introduction very easy to understand.

    Kirk's talk made me realize that RX is a very powerful abstration which can be used to build complicated asynchronous applications while still having clean, fast, and maintainable code.

  • Customization Points That Suck Less (by Michał Dominiak)

    I was really looking forward to this talk as I find it really painful to decide what kind of customization points to provide while creating a library, but unfortunately there was no "general best solution" proposed here. Michał began by covering the drawbacks of usual techniques:

    • Template specializations need to be defined in the same namespace as the thing being customized. This is problematic because multiple namespaces may need to be exited before being able to customize something.

    • ADL might require the user to pull in functions by saying using ... prior to the usage of an unqualified ADL call, which makes it really hard to write noexcept or decltype specifiers. Example:

      void foo() noexcept(noexcept(/* ??? */))
      {
          using std::swap;
          swap(a, b);
      }

    The talk then covered Haskell type classes and C++0x concepts, showing how "instances" and "concept maps" are a superior approach to generic programming. The ideas I just mentioned are very similar to Rust's trait and impl features.

    Michał finally showed the audience his template-heavy and macro-heavy implementation of concept maps, which I found both insane and impressive at the same time.

    What I personally learned from this talk is that the C++0x approach to generic programming and customization points was really powerful and it would be really sad if the currently proposed Concepts TS would prevent it from becoming a reality in the future.

saturday, may 20

  • Type-safe Programming (by Jonathan Müller)

    Excellent presentation of the ideas behind an excellent library that makes use of C++'s type system to increase safety, correctness, and maintainability.

    Jonathan guided the audience through his type-safe solutions for various problems, including:

    • Conversions between integers with different signs.

    • Signed/unsigned types for indices.

    • Strong typedefs.

    • Output parameters.

    All the solutions revolve around the idea of encoding semantic information inside types and to force potentially dangerous operations to be as explicit as possible.

    Jonathan wrote two highly-recommended amazing blog posts about the library that explain everything very well:

    I think that this talk is a must watch.

  • Nbdl: Generic Library for Managing State Seamlessly Across Network (by Jason Rice)

    The last talk I attended was an analysis of the design, implementation, and use cases of nbld, a metaprogramming-heavy framework created by the presenter that allows the creation of networked application in a declarative and type-safe manner, using as much compile-time computation as possible.

    The user of nbdl can define a compile-time Context object containing compile-time information of entities and producer/consumer actions. Messages that alter the state of the entities can then be defined in a similar declarative manner, and are automatically serialized/deserialized by the library. The can be used through a variant-like interface, via pattern-matching.

    Aynchronous events can be chained together via promise-like pipes which provide error handling through pattern matching.

    The web application that Jason used to present the slides was built with ndbl, compiled with Emscripten. At the end he showed that the generated .html file was extremely small compared to alternatives such as reveal.js due to the fact that the whole structure of the application was known at compile-time.

    I found this talk very impressive and interesting - I don't yet have a solid understanding of all the concepts behind the library yet, so I will definitely watch it again when it is uploaded and play around with nbdl's examples. I have the intuition that exploiting compile-time knowledge and metaprogramming is a great solution to the "bloat" of JS-based web/desktop applications commonly seen today which doesn't negatively impact portability.

conclusion

I had an amazing experience at C++Now 2017 and I highly highly recommend attending next year! I would like to sincerely thank all the conference staff and the speakers for a truly marvelous event, and my company (Bloomberg L.P.) for allowing me to participate while covering the costs.

Now it's time to impatiently wait for C++Now 2018...


RSS Feed