Document number: D????
Audience: WG21

Ville Voutilainen
2021-04-01

std::pony

P0592 meta-data

While this proposal does propose a couple of small language extensions and some simple library extensions, it seems completely unnecessary to waste the proposal author's time by subjecting him to the pain of talking to design-review groups, or worse, having to listen to them. Thus this proposal should be handled directly as a plenary poll item; it's amply ready for that. If you insist, it can be seen as a Bucket Zero item, because P0592 obviously includes the implicit highest-possible-priority category of "whatever the author of P0592 comes up with".

Meta-introduction

This is a proposal to lay to rest the long-standing question of whether C++ should optimize velocity or stability; the proposed std::pony allows getting all the velocity you could ever dream of, without compromising stability.

This is facilitated by introducing a new type, std::pony, that has (mostly) program-defined semantics. If unordered_map is not efficient enough for you, you can use std::pony instead. If you want a constructor overload set of std::tuple to behave differently (like, for example, to support a range like zip), just use std::pony instead of tuple and you're all set. If a standard facility would otherwise be suitable for you, but it's not efficient enough and can't be made efficient without an ABI break, just use std::pony instead. You already are using it, just with a different name and namespace.

The introduction of std::pony also allows WG21 to do sunbathing and surfing while meeting on The Big Island of Hawaii, because we don't need to waste time on reviewing library extension proposals. We can simply tell the proposal authors that they can use std::pony instead, and we'll maybe get back to their proposal if we manage to bother.

Thus std::pony also solves all of the long-term evolution and direction concerns for C++. Bjarne doesn't need to keep saying "Remember the Vasa!" any more, because we will not be adding more facilities to the standard library (unless downright exceptional motivation is provided), and thus we won't be adding complexity. The C++ standard library will be stable, manageable, and maintainable, but yet infinitely extensible.

Furthermore, std::pony removes any shadow of a doubt on whether C++ is keeping up with the times, or whether it's a viable language in the long term, or whether it's a viable language compared to its competitors. No other language will be able to provide the combination of stability and extensibility like C++ can, and the following details of the design will show how.

And, on that note of being a viable language compared to its competitors, here's a very plausible discussion you can have with aspiring C++ users:

"I want a pony!"

"Well, you're in luck, C++ has one, just use std::pony."

This will mean that C++ leapfrogs its competitors, providing such user-friendliness that it'll just blow away the competitors. Every problem domain is catered for, and all use cases that any user can imagine will be supported in a comprehensive and consistent manner.

Design Overview

This proposal has three things it proposes:

  1. two new decl-specifiers, 'my' and 'little', for the core language, and an accompanying name lookup change
  2. the main library facility itself
  3. allocator support for the main library facility

Going through those briefly, the decl-specifiers allow you to do Pony-Oriented Programming (POP):

my little pony<grin> twilight_sparkle;
twilight_sparkle.prance();
groom(twilight_sparkle);

The new decl-specifiers have no meaning other than the most important one; std::pony introduces the Pony-Oriented Programming paradigm to C++, and core language support obviously makes that support comprehensive, allowing intelligent programmers who understand the wisdom of the paradigm to program comfortably, knowing that their preferred style and paradigm is fully embraced by WG21 as the superior way to program. Furthermore, these decl-specifiers change name lookup in C++ so that you don't need to write 'std::pony', plain 'pony' will do. While it was briefly considered to just make the obvious "using namespace std;" that everybody writes anyway the implicit default in all C++ code, this approach was chosen instead after hastily pondering two alternatives and tossing a coin once, which should be a very familiar decision-making process for all members of WG21.

The main library facility itself is an infinitely extensible class template:

template <class T, class SpoilerAlert=void>
class pony
{
  friend class T;
};

The actual specializations of the primary template pony are all program-defined, with program-defined semantics, as long as they fulfill one requirement:

And finally, the reason why we have that second template parameter for pony will now become obvious; it allows supporting allocators. Allocator support for std::pony consists of two parts:

  1. a new generic allocator, called std::ponymorphic_allocator, which is almost like std::polymorphic_allocator, but much better, because it has correct propagation traits. A follow-up proposal is planned that removes std::polymorphic_allocator without bothering to deprecate it first, because std::ponymorphic_allocator is a superior replacement for every current, envisioned, and imaginary use, especially for every imaginary use.
  2. an alias in the pmr namespace that ties ponymorphic allocators to pony:
    namespace pmr {
      template <class T> using unicorn = std::pony<T, std::ponymorphic_allocator<T>>
    }            
            

The semantics of std::pony

Here we cover the three most important design aspects of std::pony.

First, the semantics of std::pony specializations are completely program-defined. This is what allows the standard library to be stable, yet allows for infinite extensibility and flexibility. It is completely up to the user to define what semantics a specialization of std::pony has. Some might ask whether that's a useful building block, but that question is obvious nonsense for two reasons:

  1. it is obviously so that the best building block is the most generic one; you can, after all, use it as a building block for anything.
  2. it is further obvious from decades of experience that nobody wants reusable concrete types that shackle you into their semantics, or heaven forbid, into some sort of API/ABI stability concerns. All anyone needs is templates, and maybe some concepts. And for those concepts, it's again obvious that what you absolutely don't want is ready-made concrete types that model the concepts, you just need the concepts and then you can write your own code for the types that model the concepts. (The standard library puts its money where its mouth is by specifying the allocator requirements but omitting any useful allocators. You're better off writing your own, anyway.)

The second thing that's barely worth mentioning is somewhat tied to the first, but not really. It would theoretically be remotely possible for a program to attempt to contain multiple different definitions of the same specialization of std::pony, especially if your codebase is polluted by idiots who don't understand that they're not supposed to write code that clashes with yours. Therefore it's remotely possible that there could be ODR violations in programs that use std::pony. This is mentioned here mostly just for completeness, just to alleviate the likely fears of the pearl-clutching and frightened members of WG21, and to show that it has been considered. Decades of experience have shown that ODR violations don't really happen pretty much ever, but once in the blue moon that they might, even novice programmers have no problem whatsoever dealing with them. Therefore any ODR concern artificially shoehorned into any discussion related to std::pony is hereby dismissed as out of order, with prejudice.

The third thing, one that some of the pedantic wannabe language designers among WG21 have surely spotted by now, is that std::pony supports class types only. It doesn't even try to work with fundamental types or enums or other such useless nonsense. The explanation for this should be, at least for its first part, blatantly obvious, but the second part is surely something that needs a careful spoon-feeding explanation here:

A future extension

Now that we've seen the greatness of the new decl-specifiers, it's highly probable that a friendly extension proposal will be written to introduce yet more decl-specifiers, namely "you", "piece", and "of", accompanied with a change to how C++ is parsed in the presence of these decl-specifiers.

The obvious use case is being able to write code such as

you little piece of s**t;

for which the obvious explanation is that s**t is just an identifier, instead of being some nonsense like multiplication of s and *t.

Pony Stables

As you can see from the heading here, these are not "tony tables". Pony Stables are quite obviously superior, and shall be used in all WG21 proposals henceforth, and the use of "tony tables" will henceforth be punishable by prompt rejection of a proposal foolish enough to try to use them, and public ridicule of the proposal author. There will also be a proposal for whatever html standardization group to remove "table" from html and replace it with "stable", for the obvious reasons. Prior to that, pull requests will be sent to all open-sauce browser projects to adopt the superior element type well before the slow and frustrating process of getting a specification change through is complete; we all know that specifications are just documentation for how an implementation behaves, anyway.

This stable will show a typical example of a programmer trying to write high-performance code with the existing unordered_map, and how std::pony will just provide a superior alternative.

Stupid legacy code Superior Pony-Oriented code
std::unordered_map<int, int> oink = foo();
static_assert(false, "This will never perform well enough, I'm quitting and going fishing");
std::terminate(); // just in case some idiot makes this compile one day; don't rmeove
std::pony<DivineOOPWrapper<int, int>> fabulous = foo();
make_lots_of_money_really_fast(fabulous);

Wording

Please don't tell me that you came this far actually expecting to find wording here.