Complex initialization for a const variable

On std-discussion, Shakti Misra asked:

I have seen in a lot of places code like
int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = some calculated value;
}
use i; //Note this value is only used not changed. It should not be changed.
But unfortunately in this case there is no way to guarantee it.
so now if some one comes and does

i = 10;// This is valid

What i was thinking: is there a way to tell that "i" can be set only once?
After that it will be a constant. Something like

const once int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = calculated value;
}
use i; //Note this value is only used not changed.
i = 10;// Compiler error

Olaf van der Spek replied:

A lambda?

I answered as follows:

Bingo. Olaf nailed it: The way to do it is with a lambda. This is one of the examples I give in my talk Lambdas, Lambdas Everywhere (here are the slides from C++ & Beyond 2010).

In your example, do this:

 

const int i = [&]{

    int i = some_default_value;

    if(someConditionIstrue)
    {
        Do some operations and calculate the value of i;
        i = some calculated value;
    }

    return i;

} (); // note: () invokes the lambda!

 

That’s the C++11 idiom for this. It’s still being absorbed though – not everyone knows about it yet as we’re still all learning C++11 styles together.

45 thoughts on “Complex initialization for a const variable

  1. Yes, as sdeetee pointed out, this is very similar to a construct used in Javascript to create an object, immediately call it and use the return value from it. in javascript it is often used as a constructor, or factory pattern, but this is also another neat way to use it.

  2. C++11 lambdas give one the opportunity to think more JavaScript-y. Now, it’s up to you whether that’s actually good or bad.

  3. As you mentioned Scala, I was going to point out in my original post that Java also accommodates this (which may be what makes it possible for Scala’s compiler back end) with its “final” keyword. Qualifying a variable as final—like using “val” rather than “var” in Scala—means that the variable must be assigned exactly once before use, not that it needs to be bound at its point of declaration.

    Given that, one can write:

    final String host;
    final int port;
    if (something) {
    host = “alpha”;
    port = 119;
    } else {
    host = “omega”;
    port = 563;
    }

  4. @Kaylyn: Hmm, which reminds me that you can always use a tuple:

    const tuple xy = [&]{ /* initialize and return a tuple */ }();

    or a struct:

    const struct xy_ { int x; std::string y; } xy = [&]{ /* initialize and return an xy_ */ }();

    Hmm… one argument in favor of these options is that if those local variables are so related that they’re initialized together, they probably ought to benefit from being grouped together anyway.

    In fact, in the case of host and port, the answer seems clear that the normal term we use for “initialize multiple variables that should be initialized together and probably share an invariants” is “constructor.” In the host+port example above, I sense that there’s a class or struct abstraction missing anyway to group these together, and once you have that you’re back in the simple single-variable case.

  5. @Steven Harris:

    If they don’t have to be const you can unpack using std::tie:

    int x;
    std::string y;

    std::tie(x, y) = SomeFunction(); // That returns std::tuple

    I don’t think it’s possible in C++, without some sort of profound language change wrt variable definition, to easily unpack and initialize multiple consts from a function :(

    Scala handles situations like this really well:

    val (a, b) = if (someConditionIstrue) {
    // Do calculations here
    (calculatedValue, someOtherCalculation)
    } else (5, 5) // Some default values

    This creates two constants `a`, and `b`, unpacked from the tuple returned by `if`

  6. @Herb I don’t want to change anything, just was wondering about the line in your code:

    the_instance = call_once( create, /* initialization, most conveniently with a lambda */ );

  7. @Arne: What would you like to change? That signature accepts call_once( flag, []{ …my lambda… } ); right? std::async is the same.

    @Jon: It can be made fast. Certainly you can do DCL, which is an atomic load (generally cheap). And before thread-safe init for function local statics was adopted, Google showed the committee a cool algorithm to do it cheaply on the fast path and promised to make the algorithm freely available for this purpose, which is what convinced the committee to adopt it as I recall. I can hunt it up in the papers but don’t have a link offhand.

  8. @Herb, Does the first singleton example you posted imply a memory barrier? If instance() is performance-critical for subsequent calls, would an alternative be to ensure the calculation is done at startup instead of on-demand?

  9. Thanks for the enlightenment about thread safety – one question to the call_once, though: As far as I can see in N3337, there is only void call_once(once_flag&, Callable, Args&&…) – is that going to change?

  10. @Arne: No, that doesn’t work. You only get automatically thread-safe initialization for *function local* statics, not for all statics because that would incur expense on a lot of code that doesn’t need it. This is described in 3.6.2/2 for those following along in the standard. The standard way to write thread-safe initialization of statics or lazy initialization, if you’re not using function local statics, is to use once_flag and call_once.

    So for example you can do a singleton as:

    // preferred unless you need fanciness like a phoenix singleton
    singleton& singleton::instance() {
    static singleton the_instance = /* arbitrarily complex init, most conveniently in a lambda */;
    return the_instance;
    }

    or as:

    // good but usually a verbose way to accomplish the same as the above
    singleton { static once_flag create; static instance* the_instance; … };
    singleton& singleton::instance() {
    the_instance = call_once( create, /* initialization, most conveniently with a lambda */ );
    return *the_instance;
    }

    or using Double-Checked Locking using a mutex and an atomic but that’s sort of the old-school way once_flag and call_once are designed to replace.

    Or another way but those are the three common variants.

    Herb

  11. What i tend to do to avoid such problems is keep such values of i under limited scope.. so basically:

    {
    int i;
    if(someConditionIstrue)
    {
    Do some operations and calculate the value of i;
    i = some calculated value;
    }

    // Do what ever you want to do with i
    } // Close scope, and forget about i

    Obviously not the ideal solution, but helps keep code clean, and variables managed..

  12. This expensive-lazy-initialisation is quite frequent in the legacy code bases I’ve dealt with (a slight improvement over repeated-initialisation – obviously there to absorb excess processing capacity).

    Where the thing to be initialised is a global computed constant, as opposed, say, a constant for an object instance, I usually extract it to a static with an initialising function, such as:

    namespace { // anonymous
    int once_calculate_i_ () { /* … */ }
    }

    void foo ()
    {
    static const int i= once_calculate_i_ ();
    // …
    }

    I don’t see an advantage in using a lambda here (and we’re unlikely to see C++11 compilers adopted for 10 years if past record is maintained – there are reasons for this in my domain).

    I would still want to see the intent of the calculation documented, which is better handled when it is expressed as a separate function. Without documentation of intent, we have to infer intent from the implementation, which is not necessarily the same thing… Poor documentation is a bane of maintaining long-term code bases, and I prefer to leave my future incarnates something more manageable.

  13. @Lachlan: I should clarify that a single instance of LazyInitialize may be shared by zero or many clients of the object. expensive_calculation() should only be called when the first client needs it.

  14. How can we solve something like this?

    class LazyInitialize
    {
    public:
    int get_value() {if (value not calculated yet) {value = expensive_calculation();} return value;}
    private:
    const_once int value;
    };

  15. The lambda solution seems appropriate for some situations, but it’s not clear that it addresses the original question.

    The original question didn’t have a default value and only conditionally initializes the variable. The lambda solution doesn’t do the same thing, since it always initializes the variable regardless of the condition.

    When I first read the question, I wondered if the intent was that i was actually a member variable (or at least persistent beyond the scope suggested), and the intent was to initialize it the first time SomeCondition was true and then never to change it again after that. In that case, the idea of “const once” seems useful.

    For example, if i was a function static, the intent might be to initialize i the first time the function is called and the condition is true, and never to change i again after that. (And also to let i remain uninitialized until that first call with the condition being true.)

    Otherwise, you could just write:

    const int i = (someCondition) ? calc() : default_value;

    This is going to be recognized by all C and C++ programmers, even those not versed in lambdas.

  16. @Herb: I think what Bruno means with statics is something like this:
    //header
    struct C {
    static int i;
    };
    //source
    int C::i = [](){ return (std::time(nullptr) % 2) ? 42 : 4711; }();

  17. I agree with the reasons given why this is better than extracting a named helper function that is only used here: the lambda has better locality, is arguably more readable, and lets you use other locals directly without passing references to an artificially outlined function. I also agree that it’s better than “const int& i = temp_i;” which is less direct and also has the drawback that temp_i stays in scope.

    @Bruno: How does this help with statics?

  18. @Andrzej: Right, but I’ll let it stand. The committee has already pretty much agreed that this should be allowed (which is why our compiler also already supports it, and with GCC and Clang that would make it de facto portable), and this extension is likely to be voted into the C++ working paper soon (this month, or September). I’ll go out on a limb and say that if anything is a slam dunk for C++14, it would seem that this is. And it truly should just work.

    Incidentally, this is one reason why I think I’ll write Exceptional C++14… 14 is so close to done (we hope to technically finalize it in September of this year), and the delta from 11 is pretty small but with a number of convenient fit-and-finish tidy-ups like this one.

  19. @Herb: While your example compiles in g++4.7, 4.8 and Clang 3.2, I believe it is not a valid C++11 code. According to sect 5.1.2 para 4, when the body of the lambda is not a simple return statement its deduced return type is void. While the expectation that this example would work is logical, and likely acceptable in C++14, C++11 seems to refuse it.

  20. constexpr keyword has been added for this purpose isn’t it? Using a named constexpr function is a good way to achieve the result.
    Even if it adds a name in the symbol space, it could (it should in fact) be a private function within the class we’re working in.

    Though, I admit that the lambda solution is a nice one I too.

  21. While technically the lambda is a good solution and may have its applications for initializations, in this case I’d as well recommend using a separate function. When the main task of a function is to *use* i, then the SRP demands separating the calculation of the initial value of i from the function. That way the main logic of the function is not interrupted and cluttered with a multiline lambda containing the lower level logic of the constant’s calculation.

  22. @Arthur Langereis

    You are hiding the verbosity of the lambda in the ellipse.
    If you need a lambda in this context, you will certainly do at least some kind of branching, which mean for clarity your lambda will not be a one-liner. You can use terse if syntax but then there is no need for a lambda.

    With a named function, if your code looks like it’s noise in the middle of the code which use the constant, at least the code is out of the scope.
    Which is a problem as you pointed, which is why I think a lambda is still better even if it looks like noise at first.

  23. Or, in this simple case, you could just use the ternary operator:
    const int i = someCondition ? calculatedValue : defaultValue;

  24. @bsivko I like that solution. It was the one that immediately came to my mind as well. The only downside is that init_i is not scoped.

  25. One more way:

    int init_i;
    if(someConditionIstrue)
    {
    Do some operations and calculate the value of i;
    init_i = some calculated value;
    }
    const int & i = init_i;

  26. To mjklaim, why do you feel:

    const int i = [&]{ … }();

    is more verbose than something like:

    static int calcI() { … }

    const int i = calcI();

    To Johannes, In addition to not needing a name and being unique as mjklaim points out, a lambda can use scoped variables and is defined and used at the site where it is needed, making a lambda a superior choice to a non-member function in this case. Given the syntactic and semantic needs of C++, I think the current lambda notation is quite compact and the upcoming upgrades for it will only make it more seamless.

    A statement like

    const int i = [&] …expression…;

    is more terse but if you only have a single expression it won’t make sense to use a lambda in this case. How would you like to see the the construction formed? (Using wished-for C++ language changes, if necessary)

  27. The one that always troubles me is initializing two or more variables that I’d like to all be const, where their values depend on some condition that I’d prefer to only evaluate once.

    std::string/* const */ host;
    unsigned int/* const*/ port;
    if (something) {
    host = “alpha”;
    port = 119;
    } else {
    host = “omega”;
    port = 563;
    }

    The only solution I know is to wrap the related variables up in struct and write a helper function that returns an instance with the proper values base on the condition.

  28. The problem with named functions is that they have a name, so they can be used more than once.
    When it is not the intention, it is a problem. Using a lambda makes it clear that there should be only one unique specifically located use.

    Unfortunately it’s more verbose than using a named function, which can be fixed with a simpler notation.

  29. Whats wrong with a simple helper function?
    I think, in most cases a named function is a more readable solution to the problem (especially in respect of self documenting code).

    int calculateValue() { //choose a more descriptive name
    if (!someCondition)
    return default_value;

    //Do some operations and calculate the value
    return value;
    }

    ….

    const int i = calculateValue();
    use i;

    things might get messy if the helper function need lots of arguments…

  30. I’m sure all these things will become clear once Ambassador Soval gets around to finishing off his next edition.

  31. I get the point but I seriously doubt if it is an advantage. It is not much different from calling a named function. If the complex calculation has a name I would a create a function with that name and call it with the necessary parameters. It is more explicit, well-understood, reusable, and more portable. You could also use the ternery operator: const int i = (condition) ? complex_func(args) : some_default_value; With a lambda, you are saving creating a function and jumping to that part of the code. It is not modular, however. With a function, you can use that same logic in more places if you need to. I would not copy-paste the lambda. Any day, I would prefer to reduce the number braces I’ve to keep track of. lambdas add braces and a sneaky pair of parenthesis at the end.

  32. I’ve used this idiom from the beginning and it is indeed powerful.
    However, it’s still verbose compared to the initial code, so I hope more terse notations (and automatic generalization) will get in the standard ASAP.

Comments are closed.