Removing duplicate code

This is a very short follow-up to the solution for removing duplicate code based on C++ policy-based design.

As I mentioned in that article, there are times when you need something more simple. And I can think of two other solutions.

The starting point is the duplication of lines 15 and 27:

#include <cassert>

struct Object {
    int prop_1{};
    int prop_2{};
    int prop_3{};
};

void set_object_properties_1(Object& object)
{
    if (object.prop_1 == 0) {
        object.prop_1 = 1;
    }

    object.prop_2 = object.prop_1 * 4;  // duplicate

    object.prop_3 = object.prop_2 * 5 + object.prop_1 * 2;
}

void set_object_properties_2(Object& object)
{
    if (object.prop_1 == 0) {
        object.prop_1 = 3;
    }
    object.prop_1 *= 2;

    object.prop_2 = object.prop_1 * 4;  // duplicate

    object.prop_3 = object.prop_1 * object.prop_2;
}

int main()
{
    Object object_1{};
    set_object_properties_1(object_1);
    assert(object_1.prop_1 == 1);
    assert(object_1.prop_2 == 4);
    assert(object_1.prop_3 == 22);

    Object object_2{};
    set_object_properties_2(object_2);
    assert(object_2.prop_1 == 6);
    assert(object_2.prop_2 == 24);
    assert(object_2.prop_3 == 144);
}

Continue reading Removing duplicate code

C++ policy-based design

Removing duplicate code with C++ policy-based design

Lately, I’ve been interested in some C++ template topics that help me design more flexible code. I didn’t explicitly search for them, but I met some cases that led me to find new ways of solving some specific problems.

A case is code duplication. I wanted to find a pattern for some duplicate code. I started with the idea of building components that I can compose however is needed. The first draft was using some lambdas and it was somehow OK. It did the job.

Then, looking around other aspects, I remembered that a friend keeps mentioning policy-based design. I had looked over it before, but I hadn’t found the need for it. But at that moment it clicked.

Let me get into code. I’m showing an oversimplified example because I don’t want to hide the main idea with details. If your real code is just as simple as the one I’m analyzing, do not jump on the idea before considering other approaches.

To give some hints about what follows: static polymorphism, composition, compile-time strategy. There are other approaches (runtime strategy, dynamic decoration), but I wanted to solve this at compile-time.

The goal

Straight forward, I want to remove the duplicate code using C++ policy-based design. It looks complicated at first. Just have patience.

I want to stick to the goal, so I omitted good naming, encapsulation, const correctness, noexcept and other details,

The problematic code

This is the code that has a duplicate piece of code – look for “DUPLICATE LINE” on lines 15 and 27 (for simplicity, it’s just one duplicate line):

#include <cassert>

struct Object {
    int prop_1{};
    int prop_2{};
    int prop_3{};
};

void set_object_properties_1(Object& object)
{
    if (object.prop_1 == 0) {
        object.prop_1 = 1;
    }

    object.prop_2 = object.prop_1 * 4;  // DUPLICATE LINE

    object.prop_3 = object.prop_2 * 5 + object.prop_1 * 2;
}

void set_object_properties_2(Object& object)
{
    if (object.prop_1 == 0) {
        object.prop_1 = 3;
    }
    object.prop_1 *= 2;

    object.prop_2 = object.prop_1 * 4;  // DUPLICATE LINE

    object.prop_3 = object.prop_1 * object.prop_2;
}

int main()
{
    Object object_1{};
    set_object_properties_1(object_1);
    assert(object_1.prop_1 == 1);
    assert(object_1.prop_2 == 4);
    assert(object_1.prop_3 == 22);

    Object object_2{};
    set_object_properties_2(object_2);
    assert(object_2.prop_1 == 6);
    assert(object_2.prop_2 == 24);
    assert(object_2.prop_3 == 144);
}

Continue reading C++ policy-based design

Polymorphism with lambda functions

This is my 100th article and it was celebrated.

100th article

 

As I’m a fan of polymorphism, I play with different approaches on this subject. I want to find new ways of dealing with polymorphic objects under constrained scenarios. Not all of them are great, but every time I learn something new that I should or should not apply in real situations.

This time, the self-imposed context is:

    • C++11
    • Using only the standard library
    • Using std::array to have a homogenous list of objects

I want a list of objects where each object behaves differently.

struct Object {
    int id{};
    int value{};
};

std::array<Object, 2> objects;

 

But I cannot simply add a method to Object because I want a different method attached to each Object from the array. I was spinning around attaching lambdas to those objects for a while when it hit me: I could use another object to wrap my original one.

 

The wrapper knows about Object (T) and its corresponding lambda (Function)

template <typename T, typename Function>
struct Callable {
    std::function<Function> func_;
}

and it’s callable for simple use.

template <typename T, typename Function>
struct Callable {
    void operator()() {}
}

 

I use a lambda function with its first parameter being the original object (Object), the equivalent of this (think of self in Python). And any other parameters.

using MyObject = Callable<Object, void(Object&, int)>;

MyObject object{[](Object& object, int i) {
    object.id = i;
    object.value = i;
}};

 

When I call the object’s “behavior”, I pass all the arguments except “this”.

object(1);

 

How does it happen?

Callable is based on CRTP to be an Object and to pass an instance of Object (“this”) to the lambda function. It inherits from Object (template argument T) and safely casts itself to Object, thus obtaining an instance of Object.

template <typename T, typename Function>
struct Callable : T {
    template <typename... Args>
    void operator()(Args&&... args)
    {
        func_(static_cast<T&>(*this), std::forward<Args>(args)...);
    }

    std::function<Function> func_;
};

 

What’s wrong with this approach?

There are two possible deal-breakers depending on your context:

    • std::function prevents Callable to be inlined
    • Callable adds some memory overhead

And that’s it with my learning purpose experiment. Here’s the full source code: Continue reading Polymorphism with lambda functions

C++ custom allocators: My first step

C++ custom allocators are a topic I don’t get around too much. They scream performance and memory usage and that’s a place I want to be. I felt a few times I might need a custom allocator to solve particular problems around dynamic memory, but it’s not something I would just jump on.

In embedded systems, dynamic memory is often replaced by static memory to get better performance and deterministic behavior. But writing custom allocators for this is not the first approach I would have. A vector can be replaced by an array and a map by a static map, and in general, memory can be allocated on the stack.

Everything has a price

This comes with costs. Not once I would’ve used dynamic polymorphism to design a feature. Even if in C++ dynamic polymorphism is not the greatest and templates can be used to achieve compile-time polymorphism, there are moments when I would choose the dynamic version for its design simplicity.

I ask myself from time to time how I could use virtual inheritance… without allocating on the heap. Some data structures from the standard library accept a custom allocator to allow me to better control how memory is managed. And this idea of controlling how an object is being allocated is bugging me more often. So I’m making a first, small, shy step. Continue reading C++ custom allocators: My first step

To break or not to break… encapsulation

“The devil is in the details” 

A particularity of the C++ data validation concept I wrote about is passing that wrapped_value object as an argument to a function. The reason is for that wrapped value to behave like the type it wraps so that it has a natural usage. I should not know the actual value is hidden by a level of indirection, making it easy to control any mutation.

To achieve that feature, I have used the user-defined conversion function and it went smooth. I can have a wrapped value and pass it as an argument (by value or const reference) to a function:

int inc_by_value(int v) { return v + 1; }
int inc_by_const_ref(const int& a) { return a + 1; }

msd::wrapped_value<int, UpperBoundLimiter<int, 10>> value = 2;
assert(inc_by_value(value) == 3);
assert(inc_by_const_ref(value) == 3);

Pass by non-const reference

The user-defined conversion I initially implemented is the const reference overload:

operator const Value&() const noexcept { return value_; }

That’s why I can pass the wrapped value by value and const reference. To pass it as a non-const reference, I have to implement the non-const reference overload:

template <typename Value, typename... Wrappers>
class wrapped_value {
    // ...
    
    operator Value&() noexcept { return value_; }

    // ...
}

And I can pass by reference and mutate the value:

void inc_by_ref(int& a) { ++a; }

msd::wrapped_value<int, UpperBoundLimiter<int, 10>> value = 2;
inc_by_ref(value);
assert(value == 3);

or

void update(int& a) { a = 20; }

update(value);
assert(value == 10); // should be 10 because of the UpperBoundLimiter

But the last assertion fails: Assertion `value == 10′ failed. Continue reading To break or not to break… encapsulation

Check if object has method with C++20 concepts

A task executor is given tasks that it runs. A while ago I designed a small concept of a task executor that replaces dynamic polymorphism with static polymorphism. But while switching from dynamic to static I lost an aspect about the type of the task that is being passed to the executor: its shape.

The dynamic approach requires an interface that describes exactly how a task must look: what method is required and what’s that method’s signature. For the static approach, I had nothing but a compile-time error if the task does not have a required method. The error message is good, I’m OK with what I get. But I don’t have a definition of what my constraints are for the task. I don’t have a concept of my requirement.

Before C++20, things were verbose and somewhat complicated. There are some ways to write requirements using SFINAE. But I feel they are just for the compilation to fail if they are not met. As for a human to understand them, they sure need more than a glance. It feels like before understanding the requirements of a type, you first need to understand how those requirements are implemented.

I tried a few implementations myself, but I could not get them exactly as I would like them to be. I’m having in my mind the simplicity that C++20 has on the concepts topic and I wanted to be around it. So… why not give C++20 a try? I never wrote C++20 more than a few experimental lines, so I wanted to see how I could implement my need.

A stripped off executor just for the sake of the example, with a task to be executed, would be:

int executor(int input, auto&& task)
{
    return task.execute(input);
}

struct Task {
    int execute(int input) { return input + 1; }
};

int main()
{
    executor(1, Task{});
}

 

The requirements that need to be implemented by the task are:

    • It must be a type with a method named execute.
    • The method accepts an integer argument
    • and returns an integer.

And I need to define a C++20 concept that requires a type T representing the task and an int which will be the input: I call the required execute method on the task object, with the integer argument, and I verify that the return type is an integer. Continue reading Check if object has method with C++20 concepts

Learn programming, not a language. But know your language(s).

There are discussions about focusing on programming, not on a particular programming language. Choose a language you enjoy and exercise general topics that can be implemented in any programming language. Later, when you’ll need a new language, you’ll already have the knowledge of programming. And switching to a new language is easy.

It’s true, you can switch to new languages, have some patience to get to know them, and you will soon be pretty used to the syntax. It can take some time to know what a language is capable of, but being able to write more than a few lines of code won’t take an eternity.

And you can stop here. We are done. Nothing new, nothing special. The most that the lines above could give is another confirmation from another person, a boost of self-confidence if I want to use big words.

If you got to this line, maybe you thought I have more to say, it couldn’t have been just that. I think what follows is more of talking to myself, thinking out loud, because again, it’s not something new; it’s just that I don’t read often about a specific flavor of learning programming languages.

It can be critical to know, besides general programming, the language that you are using. To really know it. You can solve nice problems with any language. Until the context is not nice. Until the context kicks you in the back without knowing what hit you. It’s all about context. If correctness, performance, scalability, or ease of maintenance and extension do not matter, there’s no point to focus on them. Implement your business requirements and you’re good. But when they do matter, knowing to approach them includes knowing your language.

And I want to consider two aspects. Continue reading Learn programming, not a language. But know your language(s).

C++ learning resources from the past months

A selection of articles I’ve read and videos I’ve watched in the past months

I’m constantly learning and relearning new and old topics and I enjoy saving some resources so I can see them again later. I’m the understand-by-use type, but I can’t use everything I learn in my projects. And I want to keep some things in the back of my mind for when the moment comes, just to remember the keywords that I need.

Understanding is the key to knowledge. If I don’t understand something, I will at most get things to work, but there are many cases when it’s not enough for things to just work. And I don’t understand a lot of subjects. So I come to them again and again, maybe months or years after I have studied or worked with them, including the most basic ones.

Articles

    • An easy start with how templates generate code. You’ll see how templates can save you time writing code, but also how a lot of code can be used in your applications without you really being aware.
    • Diving into the details of how C++ resolves a function call. Names, templates, overloads.
    • C++11 introduced a lot of new language and standard library features. The very long story is in the bible, but you can read a short practical guide of what the language came up with 10 years ago.
    • And if you want even a shorter and more concise list of features including C++11, C++14, C++17, C++20, here you have a cheatsheet of modern C++ language and library features.
    • Getting from short sources to a little longer ones, you can read about all C++ core language features.
    • I really enjoy reading about good design. Although this topic has its subjective and context-dependent corners, there are some known API design mistakes.
    • I’ve read multiple times about the Rule of Five and it’s a subject I’m sure I will come back to again.

Continue reading C++ learning resources from the past months

Another type of data validation in C++

A need that I met one day was to make sure some values are being properly controlled no matter who changes them.

struct Input {
    int a;
    int b;
};
    • a must be maximum 50 – if a greater value is assigned, 50 must be set
    • b must be minimum 50 – if a lower value is assigned, 50 must be set
    • if b is greater than 100, the flow cannot continue, the execution must be stopped

The fields in the struct can be changed by multiple layers of the application, so their values must be checked after each change. Possible solutions:

    • an API that assigns and verifies the values: each layer must use the API
    • an API that only verifies the values: after each layer updates the values, the API must be used by the caller
    • setters defined on the struct: SetA(int), SetB(int)

The API solutions require extra work; someone must use the API and not forget about it otherwise bugs could be introduced. The setters solution forces the usage of those methods, but I don’t want to rely on OOP here; instead, I want to go for a data-oriented approach and keep my struct as simple as possible.

I would like for a property of the struct to be configured in such a way that every time it’s being assigned a value, that value is verified against some requirements. In larger projects with layers that need to mutate some data passed around, it might be safer to go this way instead of relying on people to remember to explicitly do something.

How it looks

Someone told me they would like to see something like this:

struct Input {
    wrapped_value<int> a;
    wrapped_value<int> b;
};

wrapped_value is a wrapper that receives any value assigned to the property it wraps and makes sure it’s valid. The type of the property is passed as a template argument to the wrapper.

a and b should behave like their original types. Wrapping them, they are no longer integers, but wrapped_values. Continue reading Another type of data validation in C++

Map with static memory

A map dynamically allocates memory on the heap for stored objects. When new objects are added to the map, new allocations are made. Not for every added object, but there are moments when the allocated memory is not enough and more is needed.

There are systems where runtime allocations are not preferred or even forbidden because they are not predictable (they depend on how data is inserted or removed) and they take time. In these cases, an approach is to use static memory, known at compile time. For this, you need to know the size of your data.

The two approaches above are the main difference between a vector (dynamic) and an array (static) of the C++ standard library.

C++ does not provide a map that uses static memory. And I started writing one for learning purposes. It’s a concept, not ready for production, with missing features, not optimized for speed and size. I just wanted a map with static memory that would help me achieve constant lookup complexity in some algorithms. And I added some map-like features.

I started by defining the need. I have some 2D points and some types of points.

enum class PointType {
    a,
    b,
    c,
    d,
    e,
};

struct Point {
    int x;
    int y;
};

And I want a list of those points, each of them associated with a type, so I can easily find a point by a given type.

PointType::a -> Point{0, 0}
PointType::b -> Point{1, 3}
PointType::c -> Point{10, 5}

I could have reached for simple approaches like an array of points and a switch on the given type. And that’s what I kind of did but in a generalized way. I’m storing the values (Point) into an array. Then, for each map access by key, I need to find the corresponding index; this would be the hash function, which I called an indexer because it generates an index for the storage array. The default indexer that I provide does a static_cast from the key to std::size_t; a custom one can be passed.

At this point, I have a simple map that receives a Key type and a Value type, just like the standard map. Using static memory, it also needs to know the size. Continue reading Map with static memory