Tuesday, 7 November 2017

Abominable Types


As I recently seemingly wasn't able to finish any of the blogpostst I started*, let's have a change of mood and begin with something simple, for example with "abominable types".

What are they? And why did I never hear of them? The answer to the first question is - they are part of C++'s strange menagerie of spooky beasts, of which there are:
  1. nasal demons 
  2. SCARY iterators 
  3. abominable types 
  4. etc... ;-) ** 
Why did I never heard of them? No idea, probably because only compiler writers and template library authors needed to know about them (except from full-time language lawyers of course!). But now, as of appearance of the proposal P0172r0 this language quirk achieved a certain publicity.

1. What they are 

I said I never heard of them, but I know at least why they are called as such - the name seems to originate from Alisdair Meredith:
So what are they again? As stated in P0172r0, this are function type bearing cv or ref qualifiers, for example:
  void foo() const;
  void foo() const volatile;
  void foo() &&;
What? We all know that we cannot define a function with a const qualifier outside of a class, so are these definitions even valid? It seems they are (in a context, more about later). As it is again stated in the told proposal the reason for their mere existence is the desire to enable the following construct:
  struct host {
     int function() const;// { return 42; }
  };

  template <typename TYPE>
  constexpr bool test(TYPE host::*) {
      return is_same_v<TYPE, int() const>;
  }

  constexpr auto member = &host::function;

  static_assert(test(member), "This is why abominations exist");
i.e. checking if some member function is const. As we can see, the problem with abominables is that they aren't function types of member functions but are not types of free functions either! They are halflings, robbed of their context, but coming to life again when provided with such.

By the way, there is a nice, little known trick exploiting the usage shown above (code copied from P0172r0):
  class rectangle {
    public:
      using int_property = int() const;  // common signature for several
methods

      int_property top;
      int_property left;
      int_property bottom;
      int_property right;
      int_property width;
      int_property height;
  };
In the words of the proposal:
"... examples ... explicitly writing these types fall into the category of showing off knowledge of the corners of compilers, and winning obfuscated coding contests."
Facebook's folly::function seems to use it in that manner nonetheless:
  using ConstSignature = ReturnType(Args...) const;

  using NonConstSignature = ReturnType(Args...);

  using OtherSignature = NonConstSignature;

2. The proposal 

Because some (very smart) library writers indeed used the abominables, there was some confusion about the exact goals of the proposal:
So what is the proposal trying to achieve?

The main concern is that when writing generic code we have to consider these function signatures on the overloads, multiplying theitr number by 6. As stated in the proposal:
"In many cases, the simplest option for handling abominable function types in a trait (or other metaprogram) is simply to state that they are not supported. The main problem here is a lack of vocabulary..." 
so you have to fight with them..***. A smaller problem is that they stand out from the type system because they are crippled (remember I called them halflings?)...

OK, I digress. The proposes changes are 1. kill abominable types, 2. make them non-functions, 3. make them regular, 4. minimal library cleanup (along the lines of 2.).

As it seems, 1. was ruled out and 2. is favored. This seems logical, as the abominables are not functions, they are halflings, so they should be demoted to something less than a function - a function-like type!

PS: Maybe there is a newer version of the proposal or a some decision about its fate by now, but as I stated at the start of this post, I just wanted to finish what I started back then.

--
* and I just hit the round number of 100 blogpost drafts... :-/
** look up some of the menagerie here!
** like in c17-features-and-stl-fixes-in-vs-2017-15-3: "std::decay now handles abominable function types (i.e. function types that are cv-qualified and/or ref-qualified)"