Skip to content

Use Case Collection

Andreas Reischuck edited this page Dec 30, 2016 · 1 revision

Some use case examples that cannot be done with existing languages or are quite hard to maintain.

constexpr usable generic string class

https://www.reddit.com/r/cpp/comments/5himv7/a_perfect_string_design_missed_it_by_that_much/

Example gist

In C++ a constexpr type has to be a literal. This allows no custom destructor, even if it does nothing.

Rebuild is build around the idea that the code that is executed at compile time should be as unrestricted as possible. We do not these limitations like C++. Any regular string class would be usable at compile time.

Sane meta programming

boost::hana wraps types & constants to allow normal looking C++ code.

This still falls down, you cannot iterate over a vector of types/tuples. The type in each iteration is different. Therefore many cases still require meta template programming.

In Rebuild we have a direct interface to the compiler constructs. All meta programming looks like regular code that acts on compile time constructs.

Debug print names in a lange enumeration

C++ does not allow us to access the names of the enum states. Therefore we have to keep a separate mapping.

A simplified example:

enum class eState { normal, hover, pressed /* many more */ };

// keep synchron to eState
constexpr const char* eStateNames[] = { "normal", "hover", "pressed" /* do not forget any! */ };

Rebuild allows us to reflect over everything.

enum is a user or library defined method. Code might look something like this. (Syntax still up for changes)

enum eState (normal, hover, pressed)

def eStateNames = &(eState.values.map_attr(name).to_array)

enum with custom attributes

C++ introduces a product type std::variant<> next year.

This allows code like this:

struct Point { int x, y; };
struct Normal {};
struct Hover { Point position; };
struct Pressed {
    Point position;
    int button;
};
using State : std::variant<Normal, Hover, Pressed>;

Looks nice. We only store the data we need for each state. Let's look at the usage.

void print(const State& state) {
    std::visit([](auto&& data) {
        // reflink: http://en.cppreference.com/w/cpp/utility/variant/visit
        using T = std::remove_cv_t<std::remove_reference_t<decltype(data)>>;
        if constexpr (std::is_same_v<T, Normal>) {
            std::cout << "Normal\n";
        } 
        else if constexpr (std::is_same_v<T, Hover>) {
            std::cout << "Hover: " 
                      << data.position.x << ' ' << data.position.y << "\n";
        }
        else if constexpr (std::is_same_v<T, Pressed>) {
            //
        }
    }, state);
}

Who is supposed to use this? You need to understand all of C++ to know what you are doing.

With rebuild this is no issue. Again enum_data is user or library implemented and can be tailored to fit your needs.

enum_data State:
    normal
    hover (position : Point)
    pressed:
        attr position : Point
        attr button : int
    end
end

fn print (state : State):
    match state:
        normal:
            print "Normal\n"
        end
        hover (position):
            print "Hover: #{position.x} #{position.y}\n"
        end
        pressed (position, button):
            print "Pressed: #{position.x} #{position.y} button #{button}"
        end
    end
end

Reflection & Serialisation

C++ and most other system language do not allow us to reflect on complex data structures. This forces us to write separate code that adds these details. Examples:

Rebuild has all the interfaces to the compiler structures. This allows us to generate very efficient and flexible serialisation code.

Domain specific languages for Scanner & Parsers

Traditionally you need to use a tool with a custom domain specific language flex, yacc and Antlr. In C++ we got boost spirit with a strange syntax and quite long compile times.

Rebuild is designed to make it easy to build custom DSLs.

For a lexer it might look like this:

lexer myLang:
  '+' -> plus
  '-' -> minus
  '\d+' -> number
end