/** * @file

Ode to local types

*/
#define SEMANTIC_CODE
#define TRY_SCOPE_MINIMIZATION
#define EXCEPTIONS_VS_NON_DEFAULT_CONSTRUCTIBLE

Exposition

However much is it sad that C++ doesn't provide local functions (not counting C++11 lambdas) it still provide local types though. Sweet. Emulation of local function via static method of local type or operator() of unnamed local type is a matter of second (and a matter of taste or requirements).

#include <iostream>
#include <string>


int main(void) {
    struct boo {
        static std::string make() { return "boo"; }
    };

    std::cout << boo::make();

    struct {
        std::string operator()() { return "meow"; }
    } make_meow;

    std::cout << make_meow();
}

Local variable without default c-tor meets exceptions

Disclaimer: I am cocky young pup who values his own wisdom more than most of design patterns, methodologies and other simple all-issue-solutions together.

Holy war on default constructors

For abstract data types without some "natural" (empty, uninitialized or just "the one") state default constructor makes no sense. It might be convenient (e. g. for use with certain STL containers) but this luxury is dearly payed for. Imposing necessity to check if "invariants" holds true for every user of such type seems not worthy to me.

const correctness

One particular specimen of type without default constructor is constant "variable". Const specifier - especially in regard to automatic (think local) "variables" is a superb safety feature without any runtime penalty. Whenever I do not plan to change variable in it's scope I try to secure it against accidental change.

Exceptions

Let's focus on exemplar situation containing both non-default-constructible type and exceptions.

class triangle {
    public:
        triangle(point a, point b, point c);
        // rest of the interface but NO DEFAULT CONSTRUCTOR
};

/** @throws std::runtime_error in case anything goes wrong */
triangle factory_function(const std::string& recipe);

void process_it() {

    try {
        const triangle my_triangle = factory_function(my_recipe);
    } catch(const std::runtime_error& e) {
        /* handle exception */
    }

    /* rest of the code */
}

Singular problem with exceptions in this case is that try block has scope semantics of regular code block defining variable scope. In above example my_triangle is completely isolated from rest of the process_it() implementation. Having both minimal try block and access to instance is impossible:

void process_it() {

    try {
        const triangle my_triangle = factory_function(my_recipe);
    } catch(const std::runtime_error& e) {
        /* handle exception */
    }

    // Ouch! I need my_triangle.
    process(my_triangle);
    /* ... */
}

Having try block as needed is also not very nice as it is obfuscating source of the exception or is downright complicating error handling:

void process_it() {

    try {
        const triangle my_triangle = factory_function(my_recipe);

        // let's thank (pick divine being to your liking) that std::runtime_error is not thrown here...
        process(user_triangle);
        if(user_was_nice) {
            store(user_triangle);

            if(is_it_wednesday()) {
                go_grab_me_a_coffee();
            } else {
                tea_time(5);
            }

            show(user_triangle, some_output_device);
       }

    } catch(const std::runtime_error& e) {
        /* handle exception */
    }
}

From this code I really have no clue which part of the code is exception to be expected from. Besides - there doesn't have to be the same way how to handle certain exception types for the whole block.

Local type to save the day!

Let me rule out one "obvious" solution first. I acknowledge that simple triangle* IS default constructible therefore declarable just outside minimal try block. It is a solution to above-mentioned issue but I really don't like the idea of unnecessary using dynamic memory.

My preferred solution is to use anonymous local type (prioritizing program correctness for now I ignore any possible runtime costs).

void process_it() {

    struct {
        triangle operator()(const std::string& _recipe) {
            try {
                return factory_function(_recipe)
            } catch(const std::runtime_error& e) {
                /* handle exception */
            }
        };
    } triangle_provider;

    const triangle my_triangle = triangle_provider(my_recipe);

    process(user_triangle);

    /* ... */

}

Basically all of the above can be done by simple free function. However such function is accessible from broader scope where it might not always make sense.

Local types are just wonderful! Order pack of six right now to get one for free!