Manu343726 / siplasplas

A library for C++ reflection and introspection
https://manu343726.github.io/siplasplas
MIT License
195 stars 27 forks source link

Add cpp::Optional type #7

Closed Manu343726 closed 8 years ago

Manu343726 commented 8 years ago

Maybe directly wrapping a variant? An unary variant with empty state can be considered an optional

template<typename T>
class Optional
{
    Optional() = default;

    template<typename... Args>
    Optional(Args&&... args) :
        _variant{T{std::forward<Args>(args)...}
    {}

    explicit operator bool() const
    {
        return !_variant.empty();
    }

    const T& get() const
    {
        if(_variant.empty())
            throw std::runtime_error{"Empty optional!"};
        else
            return _variant.get<T>();
    }

    const T* operator->() const
    {
        return &get();
    }

private:
    cpp::Variant<T> _variant;
};

cpp::Optional<int> readInt();

int main()
{
    auto input = readInt();

    if(input)
        std::cout << input.get() << std::endl;
    else
        std::cout << "No input!" << std::endl;
}
vblanco20-1 commented 8 years ago

What its the runtime overhead of this Optional template compared to just returning a pointer that could be nullptr and checking it? Will be optimized by compiler in some cases?.

vblanco20-1 commented 8 years ago

Also, why use the Optional this way, using a variant itself, instead of just doing an Optional without using the variant template.

Manu343726 commented 8 years ago

What its the runtime overhead of this Optional template compared to just returning a pointer that could be nullptr and checking it? Will be optimized by compiler in some cases?.

First of all, a pointer means a cache-miss, the first thing you should avoid if performance is your concern these days. Also nullable objects are not an option since involve dynamic allocation (With all the overhead involved). Optional types provide a type-safe cache-friendly alternative for nullable types. Finally, optional values use value semantics as any good C++ does.

Also, why use the Optional this way, using a variant itself, instead of just doing an Optional without using the variant template.

Becuase the internals (aligned storage + flag) are exactly the same, so I tried to not bloat the library. Don't forget this is for learning purposes.
However, note even similar, these are not exactly the same abstractions. Variants (Sum types) are usually implemented with different flavors:

Check N4516 for an in-depth explanation of the variant design. I picked variant as an example since it's a real problem, currently a hot topic in the C++ community, and also a quite challenging feature to write.

Actually this variant can be improved a lot. For example, currently visitation has O(n) complexity, but since types are known at compile time you can write a constexpr lookup table to do visitation. But variant already involved a lot of templates, so adding also constexpr to the mix... I'm doing this to teach people, not to make them cry and run away

Manu343726 commented 8 years ago

Closed as part of https://github.com/GueimUCM/siplasplas/pull/34/commits/e9fb1fa846d1109aa002ac4b84743e9be9dcaab6

See also https://github.com/GueimUCM/siplasplas/pull/34