Blog Archives - VittorOmeo https://vittorioromeo.info/category/blog/ Program in C++ from basic to expert! Wed, 19 Feb 2025 15:18:41 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.2 https://vittorioromeo.info/wp-content/uploads/2025/02/logo-106x106.jpg Blog Archives - VittorOmeo https://vittorioromeo.info/category/blog/ 32 32 Quake VR: Classic Shooter in Virtual Reality https://vittorioromeo.info/quakevr/ Sat, 04 Jan 2025 16:17:00 +0000 https://vittorioromeo.info/?p=188 Quake VR is a unique opportunity to immerse yourself in the legendary world of the classic 1996 shooter with full virtual reality support. Thanks to …

The post Quake VR: Classic Shooter in Virtual Reality appeared first on VittorOmeo.

]]>
Quake VR is a unique opportunity to immerse yourself in the legendary world of the classic 1996 shooter with full virtual reality support. Thanks to fan modifications and enthusiasts, the iconic game from id Software has been given new life in the VR format, offering players a whole new level of immersion.

History and Evolution of Quake VR

The original Quake was a revolutionary FPS that set standards for the genre, such as fully three-dimensional levels, fast gameplay, and networked multiplayer. With the release of VR devices, enthusiastic developers created modifications to adapt the game for VR helmets. One of the most popular versions was Quake VR based on Quake 1 Darkplaces Engine, supporting Oculus Quest, Valve Index, HTC Vive and other devices.

Quake VR features

  • Full support for VR controls – free movement system, teleportation and the ability to use controllers as weapons.
  • 3D depth effect – a sense of real scale of levels, monsters and environments.
  • Original atmosphere and improved graphics – support for HD textures, dynamic lighting and anti-aliasing.
  • Mod support – the ability to add new levels, weapons and effects.
  • Co-op and multiplayer – some builds allow you to play in VR with friends.

Is Quake VR worth playing?

If you are a fan of classic shooters and are looking for new emotions from a time-tested game – Quake VR is definitely worth a try. It’s a unique opportunity to travel back to the 90s, but with a modern level of immersion that makes the game even more exciting and dynamic.

Have you tried Quake in VR yet? Share your impressions!

The post Quake VR: Classic Shooter in Virtual Reality appeared first on VittorOmeo.

]]>
Embracing Modern C++ Safely https://vittorioromeo.info/emcpps.html Fri, 11 Oct 2024 19:37:00 +0000 https://vittorioromeo.info/?p=167 “Embracing Modern C++ Safely” is a guide to using the new C++11 and C++14 features effectively, avoiding common mistakes and potential risks. Drawing on years …

The post Embracing Modern C++ Safely appeared first on VittorOmeo.

]]>
“Embracing Modern C++ Safely” is a guide to using the new C++11 and C++14 features effectively, avoiding common mistakes and potential risks.

Drawing on years of experience with large mission-critical projects, four leading C++ experts have categorized the language’s features into three groups:

  • Safe – easy to use, difficult to make mistakes in their application, and provide significant value.
  • Conditionally safe – have high value but require deep understanding and experience to use safely.
  • Dangerous – have an unfavorable risk-to-benefit ratio, easily lead to errors, and are justified only in rare specialized cases.

This book gathers the C++ community’s experience with C++11/14 features and helps you make informed decisions that consider the real balance between safety, efficiency, and complexity in large-scale software projects. The author team has analyzed real code bases to objectively demonstrate the pros and cons of each innovation.

After reading this book, you will be able to:

  • Understand how the key features of C++11/14 work and in which situations it is best to apply them.
  • Avoid critical errors and take into account non-trivial nuances of the language.
    Identify features that require additional training, experience, and collective review.
  • Develop coding standards and style guides appropriate for your team.
  • Competently and incrementally incorporate modern C++ features into existing projects.

The book will be useful for experienced C++ developers, team leaders, and technical managers who want to improve productivity, code quality, and long-term code maintenance.

Translated with DeepL.com (free version)

The post Embracing Modern C++ Safely appeared first on VittorOmeo.

]]>
Continuations Without Memory Allocation https://vittorioromeo.info/index/blog/zeroalloc_continuations_p0.html Sat, 27 Jul 2024 17:09:00 +0000 https://vittorioromeo.info/?p=158 One of the main advantages of future (or promise, depending on the language used) is the ability to compose them via asynchronous continuations. Consider an …

The post Continuations Without Memory Allocation appeared first on VittorOmeo.

]]>
One of the main advantages of future (or promise, depending on the language used) is the ability to compose them via asynchronous continuations. Consider an example:

// pseudocode
auto f = when_all([]{ return http_get(“cat.com/nicecat.png”); }
[]{ return http_get(“dog.com/doggo.png”); })
.then([](auto p0, auto p1)
{
send_email(“mail@grandma.com”, combine(p0, p1))
});

f.execute(some_scheduler);

In this example, HTTP requests can be executed in parallel (depending on the scheduler’s operation, such as thread pooling). Once both requests are completed, a lambda function is automatically called with their results.

This model is convenient because it allows us to define oriented acyclic graphs of asynchronous computations in a clean and clear syntax. This is why the std::future standard is evolving to support .then and when_all. These features are included in the N4538 “Extensions for concurrency” proposal and were excellently presented by Anthony Williams in his talk “Concurrency, Parallelism and Coroutines” at ACCU 2016.

Hidden overhead

Consider the std::experimental::future::then signature:

template
auto std::experimental::future::then(F&&& func)
-> std::experimental::future< std::result_of_t(std::experimental::future)>
>;

The return type is again std::experimental::future, which means that the continuation is typed via future. A possible implementation of then might look like this:

template
auto then(std::experimental::future& parent, std::launch policy, F&&& f)
-> std::experimental::future< std::result_of_t&)>
>
{
return std::async(std::launch::async, [
parent = std::move(parent),
f = std::forward(f)
]
{
parent.wait();
return std::forward(f)(parent);
});
}

The use of std::async and type erasure hint at possible allocations. Let’s evaluate their value.

I wrote five .cpp files, using boost::async and boost::future, where I created a chain of .then continuations starting at zero and ending at four. For example:

// zero continuations
int main()
{
return boost::async([]{ return 123; }).get();
}
// one continuation
int main()
{
return boost::async([] { return 123; })
.then([](auto x) { return x.get() + 1; })
.get();
}

Alternative design

Instead of erasing types, you can preserve them by avoiding allocations and retaining the ability to compose asynchronous computations. Consider the following variant:

int main()
{
auto f = initiate([]{ return 1; })
.then([](int x){ return x + 1; })
.then([](int x){ return x + 1; });

f.execute(/* some scheduler */);

}

With a fully synchronous scheduler:

struct synchronous_scheduler
{
template
decltype(auto) operator()(F&&& f) const
{
return f();
}
};

The compiler generates only 2 lines of assembly code! And with std::async scheduler:

struct asynchronous_scheduler
{
template
decltype(auto) operator()(F&&& f) const
{
auto fut = std::async(f);
return fut.get();
}
};

891 lines of code are generated – but that number doesn’t grow when you add extensions, since the compiler can inline calls!

Implementation

Function initiate:

template
auto initiate(F&&& f)
{
return node{std::forward(f)}
}

Template class node:

template
struct node : F
{
template
node(FFwd&&& f) : F{FWD(f)} {}
template <typename FThen>
auto then(FThen&&& f_then);

template <typename Scheduler>
decltype(auto) execute(Scheduler&& s) &
{
return s(*this);
}

};

Implementation .then:

template
auto then(FThen&&& f_then)
{
return node{[
parent = std::move(*this),
f_then = FWD(f_then)
]() mutable -> decltype(auto)
{
return f_then(static_cast(parent)());
}};
}

This approach eliminates allocations and simplifies compiler optimization. In the next article we will analyze when_all and thread pooling.

Thank you for your attention!

The post Continuations Without Memory Allocation appeared first on VittorOmeo.

]]>
Capturing Perfectly-Forwarded Objects in Lambdas https://vittorioromeo.info/index/blog/capturing_perfectly_forwarded_objects_in_lambdas.html Mon, 08 Jul 2024 04:27:00 +0000 https://vittorioromeo.info/?p=161 Perfect forwarding is a powerful feature in C++ that allows template functions to retain the lvalue/rvalue nature of their arguments. This helps prevent unnecessary copies …

The post Capturing Perfectly-Forwarded Objects in Lambdas appeared first on VittorOmeo.

]]>
Perfect forwarding is a powerful feature in C++ that allows template functions to retain the lvalue/rvalue nature of their arguments. This helps prevent unnecessary copies and enables reference semantics without requiring multiple overloads. However, capturing perfectly-forwarded objects in lambdas can lead to unexpected results if not handled correctly.

This article explores the nuances of perfect forwarding within lambda captures, identifying potential pitfalls and presenting an elegant solution.

What We’ll Cover:

  • Why using std::forward in lambda captures can cause unexpected behavior.
  • Implementing a wrapper to correctly handle perfect forwarding in lambdas.
  • Using macros to reduce verbosity.
  • Extending the solution to variadic argument packs.

The Problem

Consider the following struct definition:

struct A
{
    int _value{0};
};

Now, let’s define a lambda function:

auto foo = [](auto& a)
{
    return [&a]{ ++a._value; };
};

Using foo with an instance of A behaves as expected:

A my_a;
foo(my_a)();
std::cout << my_a._value << "\n"; // Prints `1`

Now, let’s generalize foo to use perfect forwarding:

auto foo = [](auto&& a)
{
    return [a = std::forward<decltype(a)>(a)]() mutable
    {
        ++a._value;
        std::cout << a._value << "\n";
    };
};

Unexpected Behavior

While this works for rvalue references:

auto l_inner = foo(A{});
l_inner(); // Prints `1`
l_inner(); // Prints `2`

It fails for lvalue references:

A my_a;
auto l_inner = foo(my_a);
l_inner();
l_inner();
std::cout << my_a._value << "\n"; // Prints `0` (unexpected)

Why Does This Happen?

The issue lies in how lambda captures work. When we use a = std::forward<decltype(a)>(a), a is always captured as a value, not a reference. This means mutations inside the lambda do not affect the original object.

The Solution: A Capture Wrapper

To ensure the correct behavior, we introduce a wrapper class that can store either a reference or a value, depending on how it is initialized.

Implementing fwd_capture_wrapper

template <typename T>
struct fwd_capture_wrapper : impl::by_value<T>
{
    using impl::by_value<T>::by_value;
};

// Specialized version for references

template <typename T>
struct fwd_capture_wrapper<T&> : impl::by_ref<T>
{
    using impl::by_ref<T>::by_ref;
};

The implementation details of by_value and by_ref are:

template <typename T>
class by_value
{
private:
    T _x;

public:
    template <typename TFwd>
    by_value(TFwd&& x) : _x{std::forward<TFwd>(x)} {}

    auto& get() & { return _x; }
    const auto& get() const& { return _x; }
    auto get() && { return std::move(_x); }
};

For references, we use std::reference_wrapper to avoid issues with copying:

template <typename T>
class by_ref
{
private:
    std::reference_wrapper<T> _x;

public:
    by_ref(T& x) : _x{x} {}

    auto& get() & { return _x.get(); }
    const auto& get() const& { return _x.get(); }
    auto get() && { return std::move(_x.get()); }
};

We define a helper function for easy usage:

template <typename T>
auto fwd_capture(T&& x)
{
    return fwd_capture_wrapper<T>(std::forward<T>(x));
}

Updating foo

auto foo = [](auto&& a)
{
    return [a = fwd_capture(std::forward<decltype(a)>(a))]() mutable
    {
        ++a.get()._value;
        std::cout << a.get()._value << "\n";
    };
};

This ensures correct behavior for both lvalue and rvalue references.

Reducing Noise with Macros

Using std::forward and fwd_capture explicitly can be cumbersome. We define a macro:

#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
#define FWD_CAPTURE(...) fwd_capture(FWD(__VA_ARGS__))

Now, we can simplify foo:

auto foo = [](auto&& a)
{
    return [a = FWD_CAPTURE(a)]() mutable { /* ... */ };
};

Supporting Variadic Argument Packs

If foo takes multiple arguments, capturing them correctly requires additional handling:

auto foo = [](auto&&... xs)
{
    return [xs_pack = std::make_tuple(FWD_CAPTURE(xs)...)]() mutable
    {
        std::apply([](auto&&... xs)
        {
            ((++xs.get()._value, std::cout << xs.get()._value << "\n"), ...);
        }, xs_pack);
    };
};

This allows foo to handle multiple perfectly-forwarded arguments while maintaining reference semantics.

A Simpler Alternative

An even simpler approach is to directly use std::tuple as the wrapper:

template <typename... Ts>
auto fwd_capture(Ts&&... xs)
{
    return std::tuple<Ts...>(FWD(xs)...);
}

Accessing the captured values requires std::get:

template <typename T>
decltype(auto) access(T&& x)
{
    return std::get<0>(FWD(x));
}

This approach achieves the same goal with significantly less boilerplate.

Conclusion

Capturing perfectly-forwarded objects in lambdas requires careful handling to maintain the correct reference semantics. Using a wrapper like fwd_capture_wrapper or leveraging std::tuple provides an effective solution. Macros help reduce verbosity, and extending the approach to variadic arguments ensures flexibility.

By understanding these nuances, C++ developers can write more robust and efficient generic code when working with lambda captures and perfect forwarding.

The post Capturing Perfectly-Forwarded Objects in Lambdas appeared first on VittorOmeo.

]]>
Zero-Overhead C++17 Currying & Partial Application https://vittorioromeo.info/index/blog/cpp17_curry.html Wed, 03 Jan 2024 20:49:00 +0000 https://vittorioromeo.info/?p=173 Modern C++ standards introduce powerful features that enable functional programming patterns to flourish. Among these, currying and partial application stand out as particularly useful techniques. …

The post Zero-Overhead C++17 Currying & Partial Application appeared first on VittorOmeo.

]]>
Modern C++ standards introduce powerful features that enable functional programming patterns to flourish. Among these, currying and partial application stand out as particularly useful techniques.

In this article, we will:

  • Explain the concepts of currying and partial application.
  • Implement a generic constexpr zero-overhead curry function in C++17.
  • Analyze the generated assembly to demonstrate the lack of overhead.

Understanding Currying

Currying is a technique in which a function that takes multiple arguments is transformed into a sequence of functions, each taking a single argument.

Example: Non-Curried vs. Curried Function

A simple function with three parameters:

auto add3(int a, int b, int c) {
    return a + b + c;
}
add3(1, 2, 3); // Returns 6.

A curried version:

auto curried_add3(int a) {
    return [a](int b) {
        return [a, b](int c) {
            return a + b + c;
        };
    };
}
curried_add3(1)(2)(3); // Returns 6.

Benefits of Currying

Currying allows for incremental argument binding, improving readability and reducing redundancy:

auto add2_one = curried_add3(1);
auto add1_three = add2_one(2);

add1_three(3); // Returns 6.
add1_three(4); // Returns 7.

This can be useful in practical scenarios such as filtering or searching through a collection:

std::vector<std::string> names{/* ... */};

auto find_in_names = curried_find(std::begin(names))(std::end(names));
auto jack = find_in_names("Jack");
auto rose = find_in_names("Rose");

Understanding Partial Application

Partial application refers to fixing a subset of a function’s arguments, returning another function with a reduced number of arguments.

Example: Partial Application

partial_add3(1, 2, 3);  // Returns 6.
partial_add3(1)(2, 3);  // Returns 6.
partial_add3(1, 2)(3);  // Returns 6.
partial_add3(1)(2)(3);  // Returns 6. (Currying!)

This can be implemented in C++17 using recursion, variadic templates, if constexpr, and fold expressions:

template <typename... Ts>
auto partial_add3(Ts... xs) {
    static_assert(sizeof...(xs) <= 3);

    if constexpr (sizeof...(xs) == 3) {
        return (0 + ... + xs);
    } else {
        return [xs...](auto... ys) {
            return partial_add3(xs..., ys...);
        };
    }
}

Implementing a Generic curry Function

We aim to write a curry function that:

  • Enables currying and partial application for any function object.
  • Is constexpr-friendly when applicable.
  • Introduces zero overhead compared to manual implementations.

Declaration

template <typename TF>
constexpr decltype(auto) curry(TF&& f);

The return type decltype(auto) ensures that the final function call retains the exact return type of the original function.

Definition

template <typename TF>
constexpr decltype(auto) curry(TF&& f) {
    if constexpr (std::is_invocable_v<TF>) {
        return std::forward<TF>(f)();
    } else {
        return [xf = std::forward<TF>(f)](auto&&... partials) mutable constexpr {
            return curry([
                partial_pack = std::tuple{std::forward<decltype(partials)>(partials)...},
                yf = std::move(xf)
            ](auto&&... xs) constexpr -> decltype(auto) {
                return std::apply([&yf](auto&&... ys) -> decltype(auto) {
                    return std::invoke(yf, std::forward<decltype(ys)>(ys)...);
                }, std::tuple_cat(partial_pack, std::tuple{std::forward<decltype(xs)>(xs)...}));
            });
        };
    }
}

How It Works

  1. The base case executes the function when all required arguments are present.
  2. Otherwise, the function returns a lambda that captures partial arguments and recursively calls curry.
  3. Arguments are stored in a tuple and applied using std::apply.

Performance Analysis

To verify that curry introduces no overhead, we compare generated assembly for direct calls vs. curried calls.

Benchmark Code

constexpr auto sum = [](auto a, auto b, auto c, auto d, auto e, auto f, auto g, auto h) constexpr {
    return a + b + c + d + e + f + g + h;
};

constexpr auto expected = sum(0, 1, 2, 3, 4, 5, 6, 7);

constexpr auto s0 = curry(sum)(0, 1, 2, 3, 4, 5, 6, 7);
constexpr auto s1 = curry(sum)(0)(1, 2, 3, 4, 5, 6, 7);

Results

Optimization LevelBaseline (Lines)curry (Lines)Overhead
O014140%
O1220%
O2220%
O3220%
Ofast220%

No additional overhead is introduced when using curry.

Compiler Bugs & Issues

While curry is efficient, it exposes some compiler limitations:

  • Some versions of g++ crash with internal errors.
  • clang++ has issues handling the recursion depth.

These issues have been reported:

  • GCC bug #78006
  • Clang bug #31435

Conclusion

C++17 allows for a zero-overhead, generic curry implementation that supports both currying and partial application. The assembly analysis confirms that modern compilers optimize curry effectively. Despite some compiler issues, curry is a powerful tool for functional programming in C++.

The post Zero-Overhead C++17 Currying & Partial Application appeared first on VittorOmeo.

]]>
Download OpenHexagon v1.92 – Arcade Games for Hardcore Lovers https://vittorioromeo.info/downloads/openhexagon/openhexagonv1927z/ Sat, 30 Dec 2023 06:13:00 +0000 https://vittorioromeo.info/?p=185 OpenHexagon v1.92 is the latest version of the popular open source arcade game inspired by Super Hexagon. This version features improved performance, bug fixes, and …

The post Download OpenHexagon v1.92 – Arcade Games for Hardcore Lovers appeared first on VittorOmeo.

]]>
OpenHexagon v1.92 is the latest version of the popular open source arcade game inspired by Super Hexagon. This version features improved performance, bug fixes, and new features for creating custom levels.

What’s new in version 1.92?

  • Improved optimization and stability.
  • Fixed bugs with animation and controls.
  • Improved support for Lua scripts for modding.
  • Added new patterns and difficulty settings.

Where to download OpenHexagon 1.92?

You can download OpenHexagon v1.92 for free on the following platforms:

  • GitHub – official repository with source code and latest updates.
  • Itch.io – version for Windows, macOS and Linux.
  • Steam (if available) – keep an eye on the community for updates.

If you like fast-paced arcades with hardcore gameplay and modding capabilities, OpenHexagon v1.92 is a great choice. Good luck with your playthrough!

The post Download OpenHexagon v1.92 – Arcade Games for Hardcore Lovers appeared first on VittorOmeo.

]]>
OpenHexagon: a Dynamic Open Source Arcade Game https://vittorioromeo.info/openhexagon.html Tue, 28 Nov 2023 22:54:00 +0000 https://vittorioromeo.info/?p=182 OpenHexagon is an addictive and challenging arcade game inspired by Super Hexagon by Terry Cavanagh. The game offers players a test of reaction, coordination, and …

The post OpenHexagon: a Dynamic Open Source Arcade Game appeared first on VittorOmeo.

]]>
OpenHexagon is an addictive and challenging arcade game inspired by Super Hexagon by Terry Cavanagh. The game offers players a test of reaction, coordination, and sense of rhythm, forcing them to maneuver through ever-narrowing patterns of hexagonal obstacles.

Gameplay and Features

In OpenHexagon, the player controls a small triangle that rotates around a central point. The goal is simple – survive as long as possible by dodging approaching walls. Over time, the speed increases and the patterns become more complex, turning the game into a true test of reflexes.

Main features:

  • High complexity and dynamics – even the slightest mistake can lead to defeat.
  • Synchronization with music – levels are based on the rhythm of the soundtrack.
  • Mod support – players can create and upload their own levels.
  • Open source – the project is developed by the community and is constantly updated.

Level editor and modifications

One of the key differences between OpenHexagon and the original Super Hexagon is the built-in level editor. Thanks to Lua scripts, users can create their own unique patterns, modify the game’s behavior, and even add new mechanics.

Development and Community

The game is an open-source project and is distributed under a free license. The source code is available on GitHub, and the developers encourage the community to participate in the development of the game, creating new levels and improving the mechanics.

If you like fast, challenging arcades, OpenHexagon is a great choice!

The post OpenHexagon: a Dynamic Open Source Arcade Game appeared first on VittorOmeo.

]]>
VR and SFML: How Do They Fit Together? https://vittorioromeo.info/index/blog/vrsfml.html Sun, 03 Sep 2023 00:06:00 +0000 https://vittorioromeo.info/?p=155 SFML (Simple and Fast Multimedia Library) and VR (Virtual Reality) is not the most obvious combination, as SFML is primarily focused on 2D graphics and …

The post VR and SFML: How Do They Fit Together? appeared first on VittorOmeo.

]]>
SFML (Simple and Fast Multimedia Library) and VR (Virtual Reality) is not the most obvious combination, as SFML is primarily focused on 2D graphics and multimedia, whereas VR requires working with 3D graphics and specialized APIs. However, some ways of integration are possible:

Using SFML for input and output processing

  • SFML can be used to control windows, handle keyboard, mouse, gamepad and audio events.
  • You can combine SFML with OpenVR or OpenXR to work with VR devices.

Combining SFML with OpenGL

  • SFML supports integration with OpenGL, and OpenGL can be used to render 3D scenes.
  • You can create VR rendering through OpenGL and use SFML for auxiliary functions (e.g., rendering the interface in 2D).

Using SFML for 2D interfaces in VR

  • You can use SFML to render 2D elements (HUD, menus, notifications) and display them in the 3D space of the VR world.

Binding with external VR frameworks

  • You can use SFML for the main application loop, and OpenVR/OpenXR to work with VR helmets.
  • SFML can be responsible for audio and input, and 3D rendering can be handed over to specialized VR libraries.

Conclusion

SFML itself is not designed for VR, but it can be used as an auxiliary library. If the main goal is to develop a VR game or application, it is better to use OpenXR, OpenVR, or engines with VR support (such as Unity or Unreal Engine). However, if you need to add a 2D interface or multimedia features to a VR application, SFML can be useful.

The post VR and SFML: How Do They Fit Together? appeared first on VittorOmeo.

]]>
ADT vs. Exceptions in Programming https://vittorioromeo.info/index/blog/adts_over_exceptions.html Fri, 30 Jun 2023 23:22:00 +0000 https://vittorioromeo.info/?p=148 In programming, error management and handling unexpected situations play a key role. There are two main approaches to error handling: using ADT (Abstract Data Types) …

The post ADT vs. Exceptions in Programming appeared first on VittorOmeo.

]]>
In programming, error management and handling unexpected situations play a key role. There are two main approaches to error handling: using ADT (Abstract Data Types) and using Exceptions. Both approaches have their advantages and disadvantages, and the choice between them depends on the requirements of a particular project, programming language, and team preferences.

What is ADT in the context of error handling?

Abstract Data Types (ADTs) in the context of error handling are usually special types such as Result or Option that explicitly encode the possibility of an error in a function signature.

An example in Rust:

rust
fn divide(a: f64, b: f64) -> Result {
if b == 0.0 {
Err(“Division by zero”.to_string()))
} else {
Ok(a / b)
}
}

In this example, the return type Result explicitly indicates that the function may terminate either successfully (Ok(f64)) or with an error (Err(String)). Thus, the compiler forces the programmer to handle possible errors.

Languages that support functional programming, such as Haskell or Scala, also use Either, Option, and similar constructs.

Advantages of ADT:

  • Explicit error management – errors are visible in the function signature, making the code more predictable.
  • Safety – the programmer is forced to handle possible errors, otherwise the code will not compile.
  • Ease of testing – functions using ADT are easier to test because they do not cause unexpected interruption of code execution.
  • Compatibility with functional programming – ADTs integrate well with map, flatMap, match and other functional operations.

Disadvantages of ADTs:

  • Increased code complexity – you must manually check each value, handle Ok and Err, which can lead to more complex logic.
  • Probability of error “leaking” – if the programmer forgets to process Err, the error may be unnoticeably passed on to the system.
  • Complexity in imperative languages – in languages such as Java or Python, using ADT requires additional wrappers and is not always convenient.
  • Exceptions as a way of handling errors

Exceptions are a mechanism to interrupt normal program execution when an error occurs and pass control to an exception handler.

An example in Python:

python
def divide(a: float, b: float) -> float:
If b == 0:
raise ValueError(“Division by zero”)
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f “Error: {e}”)

In this example, if b == 0, raise ValueError is called, which automatically passes control to the except block.

Advantages of exceptions:

  • Code simplification – no need to return Result explicitly, you can just call functions and handle errors only where needed.
  • Multi-layer support – exceptions can be “thrown” through abstraction layers without changing function signatures.
  • Good support in OOP languages – most object-oriented languages (Java, Python, C#) have built-in exception mechanisms.

Disadvantages of exceptions:

  • Implicit error control – a function call can end with an exception even if it is not specified in the function signature.
  • Performance – exception handling is more expensive than ADT handling, especially in languages where exceptions are rarely used (e.g., C++).
  • Easy to ignore – programmers can forget to handle an exception, which can lead to unexpected failures.

When to use ADT and when to use exceptions?

Use ADT if:

  • You develop code in a functional style (Rust, Haskell, Scala).
  • You need strict error typing.
  • You want to avoid unexpected program crashes.

Use exceptions if:

  • You are working in an OOP language (Java, Python, C#).
  • Errors are truly exceptional situations and not part of the expected flow of execution.
  • It is important for you to write concise code with minimal explicit error checking.

Conclusion

The choice between ADT and exceptions depends on the project architecture and the peculiarities of the language you use. If your goal is strict error checking and explicit error representation, ADT (for example, Result and Option) will be the best choice. But if you are interested in code simplicity and natural integration with OOP, exceptions may be a more suitable tool.

The main thing is to apply the chosen approach consistently and not to mix them chaotically to avoid confusion in the code.

The post ADT vs. Exceptions in Programming appeared first on VittorOmeo.

]]>
Safe Leaderboards in OpenHexagon https://vittorioromeo.info/index/blog/oh_secure_leaderboards.html Sat, 22 Apr 2023 06:30:00 +0000 https://vittorioromeo.info/?p=164 OpenHexagon is an addictive arcade game in which players compete for high scores by avoiding collisions with geometric obstacles. As in any competitive game, leaderboards …

The post Safe Leaderboards in OpenHexagon appeared first on VittorOmeo.

]]>
OpenHexagon is an addictive arcade game in which players compete for high scores by avoiding collisions with geometric obstacles. As in any competitive game, leaderboards play an important role, allowing players’ achievements to be compared. However, ensuring the integrity and security of these tables is not an easy task. In this article, let’s take a look at what threats exist and how you can protect the leaderboards in OpenHexagon from cheating.

Main threats to leaderboards

  1. Editing local data – players can modify their saved scores in the game files by tampering with scores.
  2. Interception and modification of network requests – data sent to the server can be altered by attackers.
  3. Using third-party software – programs that modify game behavior allow dishonest players to achieve unfair results.
  4. exploitation of bugs – bugs in game code can give unfair advantages.

Defense methods

To prevent these threats, developers can apply the following measures:

Encryption and data integrity checks

  • Use of hash functions (e.g. SHA-256) to verify changes to local files.
  • Digital signatures to authenticate data.

Secure data transfer

  • Using HTTPS or other secure protocols for data exchange between client and server.
  • Server validation of data before saving it to the leaderboard.

Server validation of results

  • Analyzing game logs to identify suspicious results.
  • Recording replays (replay systems) that allow you to check the honesty of the result.

Anti-chit systems

  • Detection of third-party software and prohibited game modifications.
  • Bans for violators and revocation of fake records.

Use of ranking systems

  • Introduce a ranking system or categorize players (e.g. by experience level) to reduce the influence of cheaters on the overall ranking.

Conclusion

Ensuring honesty in leaderboards is a constant battle against cheaters and vulnerabilities. However, a combination of server checks, data protection, and an active community can help create a fair and competitive environment for all players. OpenHexagon developers should employ modern security practices to make the game fun and fair for everyone.

The post Safe Leaderboards in OpenHexagon appeared first on VittorOmeo.

]]>