All posts by Antoine MORRIER

Having fun with Detection idiom and macros in C++

Introduction

The detection idiom is now well known in C++. However, some implementations necessitate a lot of boilerplate, and I do believe that macros may help here. So, let’s having fun with the detection idiom and macros in C++!

The goal with detection idiom in C++

The detection idiom is used to know at compile time if an expression is valid, or not. For example, it can be used to know if a class has a function, an attribute, an operator…

Our objective will be to write something like

It is easy to read. The is_valid function (actually, it will be a macro) just returns a helper function with 2 arguments that return true_type if the expression is possible or returns false_type otherwise.

Basic detection idiom in C++

To implement the idiom detection in C++, you may use polymorphic lambdas. If you chose this solution, you will need 3 things.

  1. The case where the expression is not possible
  2. The case where the expression is possible
  3. A wrapper to make things easier.

The first case is really easy

It is a function template that takes a function as a first parameter and returns false.

The second case is a bit more complicated.

The idea is simple, we test to call F with the given arguments, and we return true. The void() is used because the result of F(xs...) may returns something that implements operator,.

The third case is easy, it is just a simple wrapper.

The usage is easy, but requires a lot of boilerplate …

Making thing easier with simple macros

A simple macro could simplify things.

It is now much easier to read, however, it requires you to make a is_valid macro for each number of arguments, and it is not a good thing at all…

Going further with macros

Basics

The first thing you must understand is that recursive macros are theoretically impossible. Macros work by expansion. Each time you will expand a macro, the underlying called macros will be _painted blue_ and will not be called again. For example, if you use #define X X, when you will write X, it will not recurse until your death, it will just replace X by … X.

However, you may use indirect recursion ! Let’s make a first try

Do you think it will work? The answer is no. You expand X(), so you call X_I(). The call to X_I expands to X which is painted blue inside this expansion…

What we must do is to defer the call to X and the call to X_I and force expansion several times :

Now, we are ready. We must define an interface for our macro. I propose the following :

With such an interface, you will not be able to pass a list of arguments directly, so you must wrap them. A usual way to wrap arguments with macro is a parenthesis, so you will write is_valid((a, b, c, d), expr).

To deal with such list, the easiest way is to call another macro

This expression will lead to MACRO(a, b, c, d)

The complicate task

What will be difficult here is to create a macro that takes some arguments in a list and transform each value into auto &&x,

The goal here is to transform MACRO(a, b, c, d) into [](auto &&a, auto &&b, auto &&c, auto &&d);

An interesting idea is to create a MAP macro that takes 2 arguments. The MACRO to apply and the arguments. The macro to apply here could be a MAKE_AUTO(x).

Going that way, it is easy to understand that MAKE_AUTO(a) expands to auto &&a.

So, let’s design MAP. As I explained before, it will take 2 arguments, so we can lay:

This macro will work as follows. Take the first argument and apply the macro to it. When the tail is not empty, perform recursion on the tail. Here is my definition of MAP macro.

So, here are the explanations. The beginning is easy, you just call the MACRO with the first argument. Here is the definition of HEAD and TAILS

HEAD takes a list and returns the first element, TAIL returns the list of all elements but the first.

The second line is where the black magic occurs. Here are some high-level explanations before showing the code.

  • WHEN(c)(expr) will expand to expr only if c == 1
  • NOT(x) will expands to 1 if x == 0 and to 0 if x == 1
  • IS_EMPTY(args) will expand to 1 if the list of args is empty or 0 otherwise
  • DEFER_TWICE is needed because WHEN already make one expansion.
  • MAP_I adds a , and call MAP again

When you develop using macros, I advice you to use these 2 helpers:

The CAT macro will concat x and y, and STRINGIFY will transform arguments into a string. That may help you for debugging for example. The IMPL versions does not make expansion of arguments, but the not _IMPL versions do.

The first Macro we are going to define is NOT. It is easy to define

We use the CAT_IMPL and not the CAT version because x will be expanded here, so we do not need another level of expansion. For people coming from a functional world, it may remain pattern matching.

The second macro we are going to define is DEFER_TWICE. The idea follows the DEFER macro:

Let’s define the WHEN macro.

It is easy, we do pattern matching to a function that does nothing when c is 0, and we expand the other arguments when c is 1.

The most difficult macro to define is IS_EMPTY. I told you about an end sentinel. A simple end sentinel to use with macro is a parenthesizes. So, we just add () at the end of arguments. For example : (a, b, c, ()) represents a list that contain [a, b, c].

IS_EMPTY(x) must return 1 only when x looks like (()). Here is my solution

Now that we have an almost working solution (I said almost because MAP will not work with an empty list, but it is not difficult to fix that), we can make the definition for our is_valid macro.

The ADD_END_SENTINEL macro is easy. It just appends () to the list.

And now, we can enjoy our new function !

Conclusion

I hope you liked this article and you learned something. If you have any questions, feel free to ask, I would be glad to answer.

If you want to try it, here is the full implementation.

Thoughts about getters and setters in C++

This article deals with getters and setters in C++. I am sorry, it is not about coroutine, but part 2 of thread pools will come in the following weeks.

TL;DR: Getters and setters are bad for structure like objects.

Introduction

In this article, I will only give my opinion about them, I don’t want to offend anyone, I am just going to explain why, or why not, use getters and setters. I would be glad to have any debates in the comments part.

Just to be clear about what I am talking about when I talk about getter, I talk about a function that just returns something, and when I talk about setter, I talk about a function that just modifies one internal value, not doing any verification or other computations.

Getter performances

Let’s say we have a simple structure with their usual getter and setters:

Let’s compare this version with the one without getters and setters.

It is incredibly shorter and less error_prone. We can not make the error to return the last name instead of the first name.

Both codes are fully functional. We have a class Person with the first name, the last name, and an age. However, let’s say we want a function that returns the presentation of a person.

Show the performance differences between computation using getters by value and public access.

The version without getters performs this task 30% quicker than the version with getters. But why? It is because of the return by value of the getters functions. Returning by value makes a copy that results in poorer performance. Let’s compare the performance between person.getFirstName(); and person.firstName.

Show the performance differences between getters by value and public access.

As you can see, accessing directly the first name instead of a getter is equivalent to a noop.

Getter by const reference

However, it is possible to not return by value but return by reference instead. Going that way, we will have the same performance as without getters. The new code will look like that

Since we get the same performance as before, are we done? To answer this question, you can try to execute this code.

You may see some weird characters wrote in the console. But why? What happened when you do make().getLastName()?

  1. You create a Person
  2. You get a reference to the last name
  3. You delete Person

You have a dangling reference! It can lead to a crash (in the best case) or something worst than what can be found in a horror movie.

To deal with such a thing, we must introduce reference qualified functions.

Here is the new solution that works everywhere. You need 2 getters. One for lvalue and one for rvalue (both xvalue and prvalue).

Setter issues

There is not a lot to say in this section. If you want to achieve the best performances, you must write a setter that takes a lvalue and one that takes a rvalue. However, it is generally fine to just have a setter that takes a value that will be moved. Nevertheless, you have to pay the price of an extra move. However, that way, you cannot just make a little enhancement. You must replace the whole variable. If you just wanted to replace one A by a D in a name, it will not be possible by using setters. However, using direct access makes it possible.

What about immutable variables?

Ones will tell you to just make the member attribute as const. However, I am not ok with this solution. Indeed, making it const will prevent the move semantic and will lead to unnecessary copy.

I have no magic solution to propose you right now. Nevertheless, we can write a wrapper which we can named immutable<T>. This wrapper must be able to be :

  1. Constructible
  2. Since it is immutable, it must not be assignable
  3. It can be copy constructible or move constructible
  4. It must be convertible to const T& when being a lvalue
  5. It must be convertible to T when being a rvalue
  6. It must be used like other wrapper through operator* or operator->.
  7. It must be easy to get the address of the underlying object.

Here is a little implementation

So, for an immutable Person, you can just write:

Conclusion

I would not say that getters and setters are bad. However, when you do not need to do anything else in your getter and your setter, achieving the best performance, safety and flexibility lead to writing:

  • 3 getters (or even 4): const lvalue, rvalue, const rvalue, and if you want, non-const lvalue (even if sounds really weird since it is easier to just use direct access)
  • 1 setter (or 2 if you want to have the maximum performance)

It is a lot of boilerplate for almost anything.

Some people will tell you that getters and setters enforce encapsulation, but they don’t. Encapsulation is not just making attributes private. It is about hiding things from users, and for structure-like objects, you rarely want to hide anything.

My advice is: when you have a structure like objects, just don’t use getter and setters and go with public / direct access. To be simple, if your setter does not enforce any invariant, you don’t need a private attribute.

PS: For people who use libraries using shallow copy, the performance impact is less important. However, you still need to write 2 functions instead of 0. Don’t forget, the less code you write, the less bugged it will be, easier to maintain, and easier to read.

And you ? Do you use getters and setters? And why?