Meeting C++ 2024 Trip Report
This year marks the tenth anniversary of Meeting C++ in Berlin.
Once again my colleague and I made the decision to travel by train to the venue. The trip was very comfortable and we experienced no meaningful delays. In total, the trip took ~13 hours. I would recommend this mode of travel over flying not just for the sake of the climate (which was a very big motivating factor) but also because I just didn’t feel tired and sore the same way I feel when I fly.
Thursday (day 1)
Keynote - Fear in Tech
In his keynote, Titus Winters puts focus on the fear experienced by developers. One of the main take-aways from this is the idea of creating an environment that fosters psychological safety. To achieve this it is important to focus on people more than technical excellence.
In his opinion, psychological safety is fundamental to any team’s success
It is more important to be a good person than to be a good programer – Titus Winters
Winters also identified three types of environemnt:
- Power based: the idea that there is a chain of command to follow; removing autonomy
- Process based: every action is outcome is controlled by process; restricting creativity
- Outcome based: teams works towards a common goal
It was found that outcome based environments are generally the most successul, even with power dynamics and process in place; these can be ignored and changed in order to meet the goals.
According to DORA culture is 30%+ of success.
Winters stressed that the following points are key for success in outcome based environments:
- Documentation that aids a developer in their daily work
- Getting started
- Contributing changes
- …
- Discussing values
- Team agreements
- Boy scout rule
- Giving kudos
- Do it publicy
- If the kudos is for someone outside of the team, reach out to their manager to give kudos
- Owning mistakes
- We’re human; they happen
- Encourage the sharing of mistakes so every can benefit from them
On the topic reviewing code, Winters recommends the following set of questions:
- How will this work over time?
- How will this work for different peopl/teams/dynamics?
- What is this good for?
- What is this not good for?
I particularly like Winters’ take on tech interviews claiming they should focus on code review. The interviewers should provide the code and ask the candidate to review it. This proovides a meaningful interaction that not only demonstrates a candidates technical competence but, more importantly, gives the interviewer a chance to assess how the candidate interacts in potentially delicate social interactions.
C++ Modules
This is an intro to modules focussing particularly on *named” modules and ignoring parts of modules that do not, yet, enjoy wide implementation support.
Module names are not required to map to physical file structure. Though I would model my physical file structure after modules as I like the extra structuring.
Header units were skipped since they are not widely available.
PSA for file sets in CMake 3.23 which are important for modules in 3.28+.
Include directives are still part of most projects until Header Units become generally available. To do use we use the Global Module Fragmet:
module;
#include <vector>
export module A;
...
Andreas Weiss also demonstrated how to go about wrapping a “legacy” library in a module unit. Personally, I think this is a lot of work and would just conisder using the GMF and documenting what might to be explicitly. Daniela Engert modularized SDL and is a good source for seeing what it would take if you are interested.
Templates made easy
Interview questions (again!)
- What’s something you know that you could teach a junior?
- What’s something you don’t know, or would like to know more about?
A nice piece of advice for creating concepts is to group conceptual requirements with boolean logic
and to put requires
code inside a requires
block. This avoids accidentlly omitting the
requires
keyboard inside a requires
block.
Many great examples of applying concepts and contraints. Anyone willing to no more should really watch this video when it’s released.
Portable floating point calculations
Lots of background on lack of real compliance with IEEE-754 floating point. Guy mentioned the Goldberg paper as a good foundational reading to gain a better understanding of floating point representation and arithmetic. It’s a very interesting read.
What Every Computer Scientist Should Know About Floating-Point Arithmetic
Unfortunately there was no real solution on offer, though Guy has proposed the following papers to introduce reproducibility in C++:
There is no Silver Bullet
Iglberger takes us through an implementation using GoF patterns and transforms it with
std::variant
to remove all traces of polymorphism. After showing the impressive performance gains
we could see, he proceeds to pull the rug out from under our feet by demonstrating that the
architecture is now fully coupled.
Finally, he transforms the original example using type erasure.
This is what makes us developers; knowing these things and choosing the right solution. – Klaus Iglberger
The Famous MeetingC++ Quiz
The day rounded off with a social gathering before Diego took the stage to bend our minds with his fantastic quiz. My team scored 63 points out of 100 possible (had I not been outvoted we would have instead had an 73… Then again, if I had been paying attention in the first quiz I wouldn’t have cost my team 8 points XD).
Friday (day 2)
Centre Keynote
Hanna Dusíková talks us through the contexpr
parser of clang
. After walking us through how
clang
sees our code in constexpr
she walked us through the various containers and highlighted
constexpr
compatibility. Once it became apparent that most containers shoul be constexpr
she
challenged the room to write the papers since that is the only reason why we don’t have more
constexpr
containers in the standard. This was cemented when the list of constexpr
abilities
were listed; there is very little that cannot be constexpr
since C++20.
All of this culminated in the unveiling of HAMT (Hash Array Mapped Trie) which Dusíková would like
to see introduced to the standard once all of the constexpr
gaps are filled:
- P3068 - allowing exception throwing in constant evaluation
- P3378 - constexpr exception types
- P3309 - constexpr atomic and atomic_ref
- P3037 - constexpr
std::shared_ptr
- P3125 - constepxr pointer tagging
- P3074 - trivial unions
- P3372 - constexpr containers and adapters
- P3295 - freestanding constex rcontainers and constexpr exception types
- P3367 - constexpr coroutines
- P3391 - constexpr
std::format
- P3449 - constexpr
std::generator
- D1974 - non-transient constexpr allocations using propconst
Perhaps the coolest part of all of this (IMO) is that we could create, start, and suspend a
coroutine in a constexpr
context (i.e. at compile time) and then resume the coroutine during
runtime!
Someone asked about debugging compile time code. Dusíková suggested you could attach to the
compiler, but don’t. There are no good tools yet, but Dusíková has created her own __builtin
that
allows her to print to the compiler diagnostic output during compile time…
Pipeline Architecture with operator|
Boguslaw Cyganek demonstrated how to overload operator|
to allow for a more ranges like syntax to
support function composition. He referred to Function Programming in C++ by Ivan Čukić which is a
fantastic piece of literature if you are interested in the function programming domain.
The main point Cyganek wanted to get to was to demonstrate how std::expected
can lift the pipeline
architecture to the next level through its ability to communicate success or failure. Unfortunately,
it came undone when the different error types at different parts of the pipeline were merged in to a
std::variant
since this now couples the entire pipeline in a way that could be awkward to extend.
Perhaps I will investigate this issue further myself and see what solution I can devise.
C++ Concepts
Use static_assert
to test concepts.
Using requires Concept<decltype(arg)>
is problematic if arg
is a reference which means we also
need to use utilities like std::remove_reference_t
or std::remove_cvref_t
which we can embed in
the concept itself.
Instead of creating a concept
for everything, consider preferring:
if constexpr (requires { coll.push_back(val); }_{
coll.push_back(val);
else coll.insert(val);
which keeps the implementation details hidden where a concept
would expose them.
Josuttis also demonstrated how to use subsumption to build a hierarchy of concepts where each new level builds on the previous.
This was a very good introduction to concepts
and I would recommend watching this video when it is
released.
Software Engineering Completeness
Peter Muldoon presented his take on project management and what “done” really means. This talk is only half of the material that he has presented before. We wait with baited breath for the next installment.
In this part we heard nothing that is particularly new for a seasoned developer but it is nonetheless worth repeating as he frames it in a bastardization of Maslov’s hierarchy of need where the bottom is comprised of developers performing the minimum required to survive product development and the seond tier in which engineers are able to leverage verification and efficient planning to continually maintain a product.
In his second part he teases the final tiers in his pyramid where he turns the tables on the customer instead, encouraging developers to pose piercing questions to the customer in order to glean more insights and better estimate the work required.
Guide to C++ Object Lifetime
This was a whirlwind tour of object lifetime in C++. Mostly Müller focussed on pointers and
provenance as this is a tricky part of the language. That, and temporary lifetime extensions which
got fixed in C++20 so that temporaries in a range-for
have their lifetimes extended correctly.
On the subject of placement-new
Müller advised using std::start_lifetime_as
on the pointer to
ensure that the object is correctly constructed in place with its lifetime started.
Müller has given this presentation at conferences before and has graciously provided the material on his website already.
C++’s Next Decade
Herb Sutter took to the stage in typical enthusiastic fashion and wooed the crowd by opening his keynote in German (he translated to let everyone else in on the joke).
Sutter wants to achieve two things in the immediate future:
- focus on type and memory safety to achive parity with other languages
- Reflection and code generation
type bounds init life safe which are teh four most severe CWE categories that memory safe languages do better.
Reading unit local vars is no longer UB; it’s erroneous as of C++26. This automatically eliminates a class of bugs and does so with no action required from developers; just recompile in C++26 mode. If you are not able to run in C++26 mode yet, then GCC and Clang have a flag to set the bit pattern of uninitialised variables such that these bugs can be more readily detected by sanitizers:
-ftrivial-auto-var-init=pattern
In C++26 if, for some reason, really want an indeterminate value, then there is an attribuate for
that: int a [[indeterminate]];
We also got a friendly reminder that we have an entire subset of the language that is a UB-free
playground, namely constexpr
. With more and more things becoming possible in constexpr
(just see
the list from Dusíková’s keynote) it won’t be long before UB is removed from the language
altogether.
Attention was then turned to reflection and code generation.
Reflection is primarily static unless you opt to store it and use it runtime. This is unlike how other languages perform reflection, but it should remove any security concerns that could arise from runtime reflection.
P2996 opens the doors for Herb’s P0707 (meta classes) which will make it easy to generate correct code by default such as generating an interface based on a class definition:
class (interface) Widget {
void f();
int number();
};
which generates:
class Widget {
public:
Widget() = default;
virtual ~Widget() = default;
Widget(Widget const&) = delete;
Widget& operator=(Widget const&) = delete;
virtual void f() = 0;
virtual int number() = 0;
};
so that devs never have to remember how to correctly define the special members in an interface.
Sutter’s enthusiasm is infectious and it felt like most people in the room wanted all the things mentioned to succeed.
Saturday (day 3)
Clean Code! Horrible Performance?
Derek Jones Aura of Software Quality posits that quality is meaningless marketing jargon.
It is generally agreed that clean code improves reliabilit, security, and maintainability
Dargo claims that clean code is not the most efficient or the fastest code, but it is optimised for maintainibility, reliability, and security and challenges that the fastest code is not always the best goal
Engineering is in he crossroads of defineing and recognising what is good enough.
An interesting talk, but it lacked any connection to the real world. This felt purely hypothetical and ultimately a bit of a let down. I was rather hoping to see some empirical data and understand the argument for choosing the clean code which is assumed to be slower.
Fast and Small C++
Fertig showed how EBO works and how [[no_unique_address]]
can be used to implement something like
a compressed pair which is how std::unique_ptr
can store a pointer and stateless deleter without
being larger in size than the size of a pointer. We can achieve this custom deleters in C++20 by
using cpature-less lambdas:
tempalte <class T, class Deleter>
using unique_ptr_deleter = std::unique_ptr<T, decltype([](T* t){Deleter(t);}>;
for C++23 remove the implicit this
pointer to reduce the number of instructions caused by
indirection.
tempalte <class T, class Deleter>
using unique_ptr_deleter = std::unique_ptr<T, decltype([](T* t) static {Deleter(t);}>;
Look at fbstring
for SSO techniques
Contracts
Timur Doumler offered a detailed overview of what is coming in P2900.
Closing keynote
This closing keynote by Peter Sommerlad was a wondering of why the developers of today develop code seemingly ignorant to the learnings of the past. Indeed, when queried, not everyone raised their hands when asked about writing tests. After the keynote some developers even asked about the complexity they perceived when writing tests; an argument that simply does not hold when functions and classes are kept small and simple!
Sommerlad gave plenty of reading material that should be worth reading as a history lesson, if nothing else:
- On the Criteria to be Used in Decomposing Systems into Modules - D L Parnas 1972
- A formulation of the simple theory of types - A. Church 1940
- Refactoring Object-Oriented Frameworks - W Opdyke 1992
- Refactoring 2nd ed - Martin Fowler 2018
As if to cememt all the teachings of the past, Sommerlad walked us through the principles of good software.
Some other key takeaways inlude:
- Simplicity is the most overlooked principle
- Architetts should also implement
- Abstraction is giving a name to “stuff”. We hide details behind the name i.e. encapsulation
- Less code == more software
Do the simplest thing that could possibly work – Ward Cunningham
Lean on the type system to have the compiler give an error for design flaws in your types. Strong typing is a powerful idiom to aid with this, especially in the face of C++’s implicit conversions between types.
All in all, I feel like there was a good message here: understand how we got where we are today by studying the literature of the past. A sentiment I wholeheartedly agree with.
Sommerlad’s presentation material can be found here.
That’s all for this year
With that, the conference is over. I am taking the train back to Sweden in the morning. Meeting C++ is a really well organized conference that I have attended most years since I first visited in 2018. I intend to return next year again.