Skip to main content

Posts

Simple Template Currying

Currying is the technique of transforming a function that takes multiple arguments in such a way that it can be called as a chain of functions, each with a single argument. I've discussed Currying on this blog previously in Fun With Lambdas C++14 Style and Dependently-Typed Curried printf. Both blogposts discuss currying of functions proper. I.e., they discuss how C++ can treat functions as values at runtime.

However, currying is not limited to just functions. Types can also be curried---if they take type arguments. In C++, we call them templates. Templates are "functions" at type level. For example, passing two type arguments std::string and int to std::map gives std::map<std::string, int>. So std::map is a type-level function that takes two (type) arguments and gives another type as a result. They are also known as type constructors.

So, the question today is: Can C++ templates be curried? As it turns out, they can be. Rather easily. So, here we go... #includ…
Recent posts

Non-colliding Efficient type_info::hash_code Across Shared Libraries

C++ standard library has std::type_info and std::type_index to get run-time type information about a type. There are some efficiency and robustness issues in using them (especially when dynamically loaded libraries are involved.)

TL;DR; The -D__GXX_MERGED_TYPEINFO_NAMES -rdynamic compiler/linker options (for both the main program and the library) generates code that uses pointer comparison in std::type_info::operator==().

The typeid keyword is used to obtain a type's run-time type information. Quoting cppreference. The typeid expression is an lvalue expression which refers to an object with static storage duration, of the polymorphic type const std::type_info or of some type derived from it.std::type_info objects can not be put in std::vector because they are non-copyable and non-assignable. Of course, you can have a std::vector<const std::type_info *> as the object returned by typeid has static storage duration. You could also use std::vector<std::type_index>. st…

Chained Functions Break Reference Lifetime Extension

I discovered a reference lifetime extension gotcha.

TL;DR; Chained functions (that return a reference to *this) do not trigger C++ reference lifetime extension. Four ways out: First, don't rely on lifetime extension---make a copy; Second, have all chained functions return *this by-value; Third, use rvalue reference qualified overloads and have only them return by-value; Fourth, have a last chained ExtendLifetime() function that returns a prvalue (of type *this). C++ Reference Lifetime Extension C++ has a feature called "reference lifetime extension". Consider the following. std::array<std::string, 5> create_array_of_strings(); { const std::array &arr = create_array_of_strings(); // Only inspect arr here. } // arr out of scope. The temporary pointed to by arr destroyed here. The temporary std::array returned by create_array_of_strings() is not destroyed after the function returns. Instead the "lifetime" of the temporary std::array is extended …

Convenient deduction guides for std::function

The objective is to allow the following to be valid C++. #include <functional> struct Test { void func(int) {} }; void test() { std::function deduced = &Test::func; // compiler error std::function<void (Test *, int)> ex = &Test::func; // OK } With class template argument deduction in C++17, type arguments for std::function above should have been deduced. The first line in function testfails to compile as of this writing because std::function does not appear to have deduction guides for conversion from pointer to member functions. On the other hand, explicitly specifying the template arguments makes the compiler happy.

The following deduction guide seems to fix the issue. namespace std { // warning: undefined behavior template<class R, class C, class... ArgTypes> function(R(C::*)(ArgTypes...)) -> function<R(C*, ArgTypes...)>; } void test() { std::function deduced = &Test::func; // Now, OK std::function<void (Test *, int)&…

Inheritance vs std::variant

C++17 added std::variant and std::visit in its repertoire. They are worth a close examination. I've been wondering about whether they are always better than inheritance for modeling sum-types (fancy name for discriminated unions) and if not, under what circumstances they are not. We'll compare the two approaches in this blog post. So here it goes.

Inheritancestd::variantNeed not know all the derived types upfront (open-world assumption)Must know all the cases upfront (closed-world assumption)Dynamic Allocation (usually)No dynamic allocationIntrusive (must inherit from the base class)Non-intrusive (third-party classes can participate)Reference semantics (think how you copy a vector of pointers to base class?)Value semantics (copying is trivial)Algorithm scattered into classesAlgorithm in one placeLanguage supported (Clear errors if pure-virtual is not implemented)Library supported (poor error messages)Creates a first-class abstractionIt’s just a containerKeeps fluent interfaces…

Ground Up Functional API Design in C++

There are plenty of reasons why functional APIs look and feel different than more common object-oriented APIs. A tell-tale sign of a functional APIs is existence of a core abstraction and a set of methods with algebraic properties. The abstraction part is of course about being able to talk about just the necessary details and nothing more. The algebraic part is about being able to take one or more instances of the same abstraction and being able to create a new one following some laws. I.e., Lawfully composing smaller parts into a bigger thing that is an instance of the same abstraction the original instances were.

Composition by itself is nothing new to OO programmers. Composite, Decorator design patterns are all about putting together smaller pieces into something bigger. However, they miss out on the lawful part. Functional paradigm gives you extra guard rails so that you can bake in some well-understood mathematical properties into the abstraction.

I think most people with even b…

The video of New Tools for a More Functional C++

My previous talk on New Tools for a More Functional C++ ran into some audio issue during the meetup. I did not upload the video back then because it had no audio what-so-ever. I finally got around to record the audio track for the talk and I mixed it with the video. So here is the final video. Have fun with FP in C++!

If you don't have 35 minutes, checkout the partial video transcripts below.

Functional Programming Tools in C++ from Sumant Tambe on Vimeo.

Video Transcripts00:16
We’re going to talk about functional [programming] tools in C++ and what new capabilities exist in modern C++. 
2:00 I'm reviewing Functional Programming in C++ book by Manning---a good book for C++ programmers to acquire beginner to intermediate level knowledge of FP in C++.
2:30 Sum types and (pseudo) pattern matching in C++
5:00 Modeling a game of Tennis using std::variant
7:30 std::visit spews blood when you miss a case in the visitor. See an example. Therefore, language-supported pattern matching is muc…