C++ evolves via proposals, which involve a lot of hard work from all concerned. Teedy Deigh attempts to help by sharing her proposal for a new state for pointers, which may not get traction, but might make you smile.
Abstract
This proposal concerns the addition of a new feature to ISO C++. It involves a new keyword and some semantic changes. [Question for reviewers: Is this abstract enough? Should it be vaguer? Is specifying ‘ISO C++’ too concrete or should I instead replace it with something like ‘an existing programming language’?]
Rambling
The menagerie of programming languages is an overcrowded dog-eat-dog, cat-eat-mouse, startup-eats-your-lunch farmyard. C++ needs to both differentiate and integrate itself. Leaving aside the obviously popular languages – C, C#, Java, JavaScript, and Python, plus a couple of languages that are too young to drink or vote – C++ also needs to compete with the likes of Haskell, a language that makes up for its lack of mainstream presence by being a Millennial influencer.
In common with many other languages, C++ has exhibited – and, indeed, acted on – its fair share of FP envy, often looking wistfully at the simplicity and feature set of Haskell and other functional programming languages. For example, compile-time computation in C++ follows functional constraints and style more closely than the less pure runtime language, especially in its original template metaprogramming form. TMP started – and, some would contend, continued – as an accident, becoming anything but temporary. Apart from the frustration induced by compiler messages and the maintenance costs arising from code subtlety and obscurity, it has no side effects. The last couple of decades have seen more concepts and, of course, concept
s added to both mitigate and amplify this. Whole books and week-long training courses, for example, are now dedicated to explaining C++’s ever expanding pantheon of const
-related keywords, semantics, and surprises. Creating and meeting this demand keeps the C++ market vibrant and fizzbuzzing!
There are burgeoning opportunities for C++ compile-time programming in future thanks to the increased focus on safety. Most bugs happen as a result of side effects; ergo, eliminating side effects reduces bugs. As runtime bugs are an artefact of the runtime, favouring compile-time over runtime programming seems the logical conclusion. [Aside: Deprecating the whole of runtime C++ is not the subject of this proposal. Rest assured, however, once this proposal has been accepted, I will be working on a paper to drop the runtime language. Such a possibility should, I hope, offer a clear incentive to committee members as to how they should respond to the current proposal. Rather than merely reducing the occurrence of undefined behaviour in the C++ standard and, therefore, its incidence in C++ code, removing the runtime-related parts of the standard will have the benefit of eliminating undefined behaviour in C++, as well as radically simplifying the language and library. I’m a little surprised no one has suggested this before.]
Another example of FP envy is lambdas. These were adopted into C++11, just missing the half century anniversary of their inclusion in Lisp and jumping the footgun on their 80th birthday.
One area of FP that has received at most optional attention in C++ is monads. Haskell, for example, has the IO
monad to mark code with side effects – in C++, this is equivalent to pretty much any C++ – and the Maybe
monad to indicate an optional value – in C++, this is similar to std::optional
, but with the added elegance of Haskell and the full blessing of monadic goodness. [Question for reviewers: Some readers of previous drafts have asked for clarification of the term ‘monad’, requesting a deeper explanation of the concept and its role in programming. I thought it would be enough to say that a monad is just a monoid in the category of endofunctors, but have been told that is neither sufficient nor necessary. Suggestions?]
Meandering
This proposal concerns itself with the issue of pointers and safety. Null has been called a billion-dollar mistake. While this pales in comparison to the int
-busting cost of Crowdstrike’s unchecked off-by-one error, the issue still warrants addressing. Similarly, one attempt to reduce undefined behaviour in the language – for example, uninitialised pointers – has been to rebrand and remarket much ‘undefined behaviour’ as ‘erroneous behaviour’ and hope people buy it. I believe a less cynical and less critical path can be taken.
This proposal pursues – and pounces on – a different approach. In addition to pointing to valid memory or to null, a pointer can be in the mull state. A mull pointer reflects an uncertainty and lack of commitment that Maybe
suggests, but without the intellectuality and clarity of monads. Squinted at just right, the mull state can be considered the offspring of – or head-on collision between – JavaScript’s undefined
and IEEE 754’s NaN.
Whether dereferencing a mull pointer works or not is largely a matter of consideration. What, after all, do we mean by ‘works’? Who are we to say whether a piece of code is ‘correct’ or not? Is it not presumptuous for us to judge? There are many opportunities for interpretation here that compiler implementors may wish to ponder. Mulling implies that the program could hang indefinitely. Or perhaps it captures the spirit of the conversation between developers collectively CSI-ing a core dump, thus encouraging software development to be a more social activity. Either way, it is left to the implementor’s discretion rather than being left undefined.
As you can see, such a contemplative and reflective approach [Aside: There has to date been no discussion on how – or even whether – this should be integrated with reflection features and proposals.] sidesteps and deftly dodges questions of safety. It also takes the edge off the judgemental negativity of ‘erroneous behaviour’ and the formal snubbery of ‘undefined behaviour’.
It is easy to see, with a little overthinking and overdesign, that introducing the mull state into C++ offers many possibilities for future generalisation. For example, in addition to truth and falsehood, bool
could have a third mull state, allowing C++ to better model indecision, three-valued logic systems, and political discourse. For Unicode characters and strings the mull state could be mapped to the shrug emoji. Heavy users of floating-point numbers will surely be excited to have a new non-finite state that is beyond compare. However, much as premature generalisation is a favourite pastime of C++ developers, I will resist the temptation to dive into that rabbit warren here. [Question for reviewers: That said, I do have a fairly fully worked out preliminary draft of all these possibilities.[Aside: And, indeed, may have got slightly distracted working on that rather than this proposal, so apologies for the delay.] Please let me know if you would like to see it. Also, as the current paper concerns pointers, there is no reference section.]
Concrete
The mullptr
keyword is a constant of the mull state that is implicitly convertible to any pointer type, dumb or smart. Whether dereferencing a mull pointer results in unspecified or implementation-defined behaviour is not defined.
The declared type of mullptr
is mull_t
, which can be picked up as an std
(either namespace or module). No decision has yet been taken as to what header mull_t
should be defined in, but in keeping with existing practice it will either be something quite obvious (e.g., <mull_t>
or <mullptr>
) or somewhat surprising (e.g., <cstdint>
or <any>
). It is intended that mull_t
is to be pronounced mullet rather than mult or multi.
Handwavium
It is customary to eventually include proposed wording changes for the standard. This would be premature at this stage, but readers can be assured that there will be words. [Aside: Especially if I have to go another round with committee members who have suggested this feature is ‘frivolous’, ‘poorly thought out’, and ‘a waste of valuable committee time’.]
Like other members of Generation X, C++ isn’t showing any signs of going away. Teedy has, therefore, decided to help it be its best self. Bringing about such change typically demands deep knowledge of the language, awareness of the standardisation process, political acumen, sensitivity to other people’s opinions and taste in matters of programming and design. Teedy, however, rarely submits to the demands and expectations of others.