---
# System prepended metadata

title: 'TotW 13: Initialize with IIFEs'
tags: [C++]

---

# TotW 13: Initialize with IIFEs
Part of the [Tips of the Week](Tips-of-the-Week) series
###### tags: `C++`

### A simple scenario

Imagine you're initializing a const variable, e.g.
```cpp
const int y = x * 10 + 5;
```
sometimes the logic with which we want to initialize the variable is a bit more complex, like a convoluted ternary expression:
```cpp
const int y = condition1 ? value1 : (condition2 ? value2 : (condition3 ? value3 : value4)); 
```

Which makes for complex code.
It would be very much readable to have
```cpp
int y;
if(condition1)y=value1;
else if (condition2)y=value2;
else if (condition3)y=value3;
else y=value4;
/* now, somehow, make y const */
```
But of course, we can't do that.
Something that would look a bit nicer would be to have an initializer function, like

```cpp
int initialize_y(...);
const int y = initialize_y(...);
```
In this case, it would look like:
```cpp
int initialize_y(int value1, int value2, int value3, int value4, bool condition1, bool condition2, bool condition3) {
    if (condition1) return value1;
    if (condition2) return value2;
    if (condition3) return value3;
    return value4;
}
const int y = initialize_y(value1, value2, value3, value4, condition1, condition2, condition3);
```
Which still isn't satisfying yet - the function call itself is more verbose than the nested ternary expression we started with!

Additionally, sometimes certain initializations cannot even be expressed with a single expression, e.g.

```cpp
/*const*/ std::vector<int> sorted_values = values;
std::sort(sorted_values.begin(), sorted_values.end());
```
Only after the call to `std::sort`, `sorted_values` contains what it's supposed to. Too bad we didn't manage to make it `const`, which would have been very clean: `sorted_values` would get initialized with the correct value, and every time we'd refer to `sorted_values`, we'd be guaranteed to find in it exactly what we expect, and not at some intermediate stage of its computation.

In this case the initializer function pattern we saw above can come to the rescue, resulting in
```cpp
std::vector<int> sorted_copy(const std::vector<int>& input) {
    std::vector<int> copy = input;
    std::sort(copy.begin(), copy.end());
    return copy;
}
const std::vector<int> sorted_values = sorted_copy(values); // Yay!
```

Is there a better solution for these scenarios?




### What the heck is an IIFE?

*IIFE* stands for [Immediately Invoked Function Expression](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression).
It is simply a lambda that gets defined and called immediately, rather than being assigned to a variable or provided as argument in a function call.
```cpp
// C++
[]{/* function body */}();
```
```python
# python
(lambda: '''some expression''' )()
```

### How do they help in those scenarios?
The first scenario now becomes:
```cpp
const int y = [&]{
    if (condition1) return value1;
    if (condition2) return value2;
    if (condition3) return value3;
    return value4;
}();
```
and the second:
```cpp
const std::vector<int> sorted_values = [&]{
    std::vector<int> copy = values;
    std::sort(copy.begin(), copy.end());
    return copy;
}();
```

Using IIFEs as initializer has the best features of all the solutions presented earlier (and then some):
- Even the initialization can be expressed as an expression (e.g. our nested ternary expressions), the resulting expression can be very verbose, while with IIFEs our initialization will have the function style, which is much more readable;
- The function solution needs to declare a function somewhere else, that could be potentially far from the point of use, making for less readable code - here the function definition and its only usage are in the same point;
- The function solution for initializing `y` requires passing 7 parameters; every parameter has to be written at least three times (in the function declaration, its usage in the function body, and in the function invocation); every time we change which variable our computation will depend on, we need to modify all of these; slow and verbose; Instead with the IIFE we capture the current context with `[&]` and we don't need to worry about that. Also, since we don't take any parameter, we can omit the `()` (i.e. instead of `[&](){/*body*/}();` we can just write `[&]{/*body*/}();`);
- The function solution requires up to come up with a name for a function that in most cases doesn't have a good name other than "initializer_of_this_variable". Also, whathever name we pick, it will poluutes the current namespace, and we might even incur the risk of someone calling it - that's a no-no;
- The function solution can very often satisfy the requirements for [copy-elision](https://en.cppreference.com/w/cpp/language/copy_elision); altough with an IIFE the compiler knows that that function has exactly one call point, and will therefore inline the call to squeeze even better performance out of it (under any optimization level greater or equal than `-O2`).

Finally, we used the initialization of constant variables to motivate the use of IIFE-initializators, but there's no reason you should limit yourself to that. For instance, you could have a mutable variable that is supposed to satisfy a certain set of invariants. It might be good for that variable to satisfy those conditions from the moment it is initialized, so why not achieve that with an IIFE?


### Bonus: IIFE as static intializer blocks

For those of you who know a bit of Java, think of (static and non-static) initializer blocks; they are block of code written inside a class.
The static ones get executed on class declaration, and the non-static ones on every class instantiation.

```java
public class Test {

    static{
        System.out.println("Static block");
    }

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
        // will output:
        // Static block
        // Non-static block
        // Non-static block
    }
}
```

We don't really care much for non-static initializer blocks, as we can do that with constructors (why does Java have non-static initializer blocks? that's a different story ;) but we sometimes would like to have a way to say "I would like to run this block of code, only once, at startup, with thread safety guarantees".

We can achieve this with
```cpp
static int x = []{
    /* body */
    return 0;
}();
```
by leveraging the fact that the initialization of static variables is always executed only once, regardless of the threads behaviour in the program.
The only downsides are that we need to have a return type, and explicitely return something of that type (e.g. an int in this case) that will actually take up space in the program, and that we need to give a name to the static variable storing the result of the computation.