REPL in C++: types to the rescue
This post is a follow-up to my hands-on session article about C++ REPL.
Being able to display readable types and content for your variables and functions can greatly improve the user experience inside a C++ REPL.
This article is very short, so that you can jump to the short (2 minutes) demonstration video below. It is based on CleanType, a C++ header-only library whose intent is to get readable types and content.
For those in a hurry, you can skip to the video transcript at the end of this page.
Some links before concluding this article:
- The demo code for this REPL demo is available here
- For those who were interested in the jupyter notebook C++ REPL environment, you can also try it inside jupyter notebook (beware, this may require a minute or two to load, mybinder.org is sometimes sluggish)
- For those who prefer a demo in a more standard C++ environment, here is a simple demo, which you can also try interactively on gitpod (registration required)
Video Transcript
Note: Here is link to the same transcript as a gist, with nicer colors.
// REPL in C++: display readable types and
// variable contents.
// This demo uses cling, a fully compliant C++14 REPL,
// and asciinema, a terminal session recorder.
// It is based on CleanType (a C++ type introspection
// library)
// You can pause at any time, and copy-paste samples from it.
#include <cleantype/cleantype.hpp>
// The dumbest logger in the west...
#define LOG(...) std::cout << __VA_ARGS__ << "\n";
// First, let's define a variable for demonstration purpose
std::set<std::string> my_set { "Hello", "There"};
// let's ask CleanType to give us the type of "my_set"
// cleantype::full will return the *full* type info
LOG( cleantype::full(my_set) );
--> std::set<std::__cxx11::basic_string<char>, std::less<std::__cxx11::basic_string<char>>, std::allocator<std::__cxx11::basic_string<char>>> &
// Ouch, that was barely readable!
// cleantype::clean will return a *readable* type
LOG( cleantype::clean(my_set) );
--> std::set<std::string> &
// Let's now show the content of "my_set" together
// with its type
LOG( cleantype::show_details(my_set) );
--> std::set<std::string> & = [Hello, There]
// Yes, but what about lambdas? Could you guess
// the signature of the lambda below?
auto lambda_example = []() {
// when C++ meets js...
return +!!"";
// See https://blog.knatten.org/2018/10/12/1662
};
// cleantype::lambda_clean returns the signature of lambda functions
LOG( cleantype::lambda_clean(lambda_example) );
--> lambda: () -> int
// Ok, maybe this was too easy.
// Let's try with a generic lambda!
auto add = [](auto a, auto b) {
return a + b;
};
// Now, can we see its signature?
// Yes, we just need to specify the args types.
LOG( cleantype::lambda_clean<std::string, char>(add) );
--> lambda: (std::string, char) -> std::string
// Can CleanType understand some more complex libraries
// like range-v3 where most variables, functions
// and lambdas are of type "auto"?
// Well... yes!
#include <range/v3/all.hpp>
using namespace ranges;
auto square_yield_fn(int x) {
return ranges::yield(x * x);
}
auto squares_view = view::for_each(view::ints(1), square_yield_fn);
// What is the type of squares_view?
// Let's see...
LOG( cleantype::clean(squares_view) );
--> ranges::v3::join_view<ranges::v3::transform_view<ranges::v3::iota_view<int, void>, ranges::v3::single_view<int>(*)(int)>, void> &
// Let's make it more complex yet:
auto squares_take_10 = squares_view | view::take(10);
// As you will see below, CleanType can indent
// the types when they get more complex!
LOG( cleantype::clean(squares_take_10) );
--> ranges::v3::detail::take_exactly_view_<
ranges::v3::join_view<
ranges::v3::transform_view<
ranges::v3::iota_view<
int,
void
>,
ranges::v3::single_view<
int
> (*)(int)
>,
void
>,
false
> &
// Thanks for watching!
Comments