CppCon 2018: Adi Shavit “C++ Cryptozoology – A Compendium of Cryptic Characters :: #2”

– I’m happy to be here Thank you for joining me I hope you’re brave enough We’re gonna take a fun trip into the crypt of C++ We’re gonna see some extremely esoteric pieces of information When I give this stuff, I generally like to guarantee that most people, that everybody’s gonna learn something With this crowd, I’d settle for a large subset So, by day, I’m computer vision and AI researcher and developer By night, I give a guided tour into the dungeons of C++ So, I hope you’re brave enough to join me Otherwise, you’re free to seek out some of the other talks here C++ has some extremely colorful terminology, which I’ve been collecting over the last couple of years Although some of these are extremely rare, and very strange, I think there’s a lesson to be learned for most of them This is free participation, so feel free to shout out comments Most of you know more than I do about some of these things, because they’re so esoteric I think you know they’re more or less sorted from A to Z So, we’ll start with A Right, so abominable function types An abominable function type is a type produced by writing a function followed by a cv-ref qualifier So, we have a nice example here using abominable, the abominable is just the name void Void to const volatile ref ref So, this looks like a function declaration, but in fact it looks like a function type, but it’s not a reference It’s not const and it’s not volatile There is in fact no way to accept a function in valid C++ So, how come we have these, this type of declaration? I know some people are actually actively trying to get rid of this strange part of the type system So, I’ll show you how this is actually used Abominable function types are used to forward the clear method prototypes Let’s say I’m the very enterprising rectangle developer, and I have this fabulous truck, but it really pains me to duplicate the signatures of these six methods, right, top, left, bottom, right, width, and height So, what I’m gonna do I’m gonna be extremely clever, and I’m going to code the int property is going to be an abominable function It’s a function that takes no arguments It’s turns an integer, and is of course constant And, we’re done So, and then we just define this function, the method declaration, of these six methods Of course, the implementation will be the implementation So, I’m just showing you how to use it, but don’t say I told you to Don’t use it If you see somebody do that, in code, you kick their butt, right So, this should not pass code If you have any questions, feel free to barge in Right, so COWs Copy on Write This was very, very popular, and it’s still very popular actually for resource management in various operating system components like virtual memory, file systems, databases Basically, you have an object, copies of objects, which share the internal state until one of the copies is, somebody tries to modify it Then a copy is made So, in 1999, I found this quote for somebody called HS in the C Users Journal, 1999 It said, “To my knowledge, all of the most popular “implementations of basic string on Windows “and other platforms is COW.” So, we see COWs, just like in Switzerland, used to be very popular However, unlike Switzerland, they’re now forbidden by the C++ standard The reason is that string needs to give, whenever you need, for example, to get an iterator, pointer, or reference like a bracket operator, you need, a COW would invalidate the iterator So, they were actually forbidden But, it’s good to know, and it is still a popular idiom in knocking the standard and not for string, but it is, you might come across it in various other cases It’s also related, like many COW products, it’s related to flies and the fly weight Yeah, it has a currency Okay, Duck Typing I’m sure most of you have come across this term It talks about application of the Duck Test The Duck Test is a form of abductive reasoning I have to rewrite that term Basically, it says if it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck It originates classically from dynamically typed languages

where languages like JavaScript, or probably older languages as well, would determine the type of the class and the object only at run time, when actually at the point of trying to use, or access a member or the method Of course C++ is tactically typed, and therefore it doesn’t require a run time Duck Typing However, templates, at least until C++ 20, are statically, they are static Duck Typing inside templates So, whenever we get some kind of template parameter T, a type that we don’t know when we’re actually writing the template The only time inside the compilation where we’re checking the type of T is the extension point This is one of the reasons for getting a horrible template message One of the main motivations for concept, or I won’t say main, one of the motivations for concept is exactly to allow us to have template errors happen at the point of specification instead of point of usage So, we’re trying to get rid of ducks, Duck Typing inside C++ Now, I was trying to, so you know how they say that C++ is two incomplete languages It has, or more like two languages, or maybe five internal, two incomplete languages You know, the name programmer might say sure C++ is implemented in well, C++ right Yeah, well, apparently, like some broomsticks, C++ is quite magical A few months ago, I tweeted this rather naive tweet How many examples can you name of magical C++? It took a couple of minutes, and then the tweet storm that ensued that included like half of the C++ CPPCon speakers, past and present speakers, including many who are sitting here, with showing me what a can of worms I’ve opened So, I’d like to, some of you are quoted here The others just for lack of space, cause there were quite a few others Just to name a few, initialization lists, std::launder, most of atomic, even vector and complex types, most of type traits, typing for address, and built in functions, and of course, main itself is quite magical This is, but wait, there’s more because the compiler now generates for us So, we have integer sequences We have range forward loops We have landers We have space ship operator Yeah, maybe I should’ve put this under P for Pandora’s Box (audience laughs) Okay, so I really love this one Maximal Munch This beast actually raises its ugly head in many other languages This is a common parsing idiom Well, the standard says when the lexical analyzer takes as many characters as possible to form a valid token Otherwise, the next processing token is the longest sequence of characters that is constitute a preprocessing token, even if that would cause further lexical analysis to fail What does that mean? It means that if we have this expression like X++Y, which could be parsed as X plus positive Y, it is actually parsed as a post incrementing X, and then just the Y with no operator, which fits In fact, this is the culprit for most, if any of you remember that C++ used to have, used to require when we had two template types inside the angled bracket, we used to have to keep the space there Otherwise it would try looking for the output, like the right shift operator So, that’s one of the fixes that went in, and there are actually many other different examples where Maximal Munch creates very, very vexing parses Yeah, like there was a Stack Overflow question why doesn’t A+++++B work? I think Shafik, which I did see, yes, there he is I think he gave a very nice answer for that Okay, right, okay, so this is like very, very esoteric I’m wondering who’s seen this before Owlie eyes, anyone, anyone? Okay, okay, I came across this when I actually needed it So, that’s how come I know it I came across this So, in old versions of Microsoft Visual C, it used something like while zero, with a constant expression, you would get a warning, warning C4127,

conditional expression is constant One of the recommended solutions was to use the com operator and another zero, just to make the condition false, and then you won’t get that warning We don’t like warnings The mine usage was actually when you define MACROs, or needed some scope, and people used to recommend using Owlie Eyes So, apparently from Visual Studio 2015, they actually removed this warning for a constant like zero So, it actually, you won’t actually get it, although if I write while 42, we still get the warning So, the intent behind the warning is clear, but I guess somebody decided that while zero is frequently used enough and it makes sense for not worrying about it So, who’s seen it before, yeah? Couple of people So, this is a hoot (audience laughs) Sorry, I had to, it said here in my notes I can’t think Okay, Phantom Types You know, like many, many good super heroes, Phantom Types make types stronger Basically, we can have a template class that takes a template parameter, a type parameter, that is not actually used inside the template body Now, it might seem strange, and why would you wanna do that except for hey, I know how to use templates It is actually used a very common medium, used as a type for different type differentiations between otherwise identical types So, I have an example, and it’s actually taken from Ben’s talk last year at CPPCon So, let’s say we have formed data as a template, taking type named T, and T is our phantom type As you can see, it doesn’t actually appear anywhere inside the template So, we have these explicit instruction from a string and a string member, but T is actually, is unreferenced anywhere However, whenever I instantiate form data with any other tact type T, I’m getting totally separate types Therefore, in the example, we can have function get form data that returns the form data of honest, unsanitized, and then we can go and sanitize the data However, we can never mix up unsanitized and sanitized strings because these are totally different types Whenever we make this confusion, the compile is actually more than one So, instead of some kind of run time error, or maybe newer code, we’re going to get compile time error So, they’re actually very helpful and very good to know, but I do recommend watching Ben’s talk Right, so this, this next item comes from, there was a blog post recently from Jonathan Boccara about Poisoning Functions Nobody likes poisons, but apparently these ones do have some ability Both GCC and clang have a a custom pragma where you can poison an identifier So, that means whenever this identifier appears in your code, you get a compilation error There are some possible uses for doing that like identifying, using deprecated features, or preventing function usage by using the, for example, using these identifiers only before the pragma appears in the header file, and then anything, including this file, is forbidden from using So, that’s up to you It’s not standard It’s not portable Because it works on the identifier alone, but it doesn’t respect things like overload and namespace options So, if it sounds interesting, go check it out Check out the blog post Oh, yeah, that’s poison ivy with Batman He’s inside the poison ivy Right, so, again Twitter is an endless source of interesting information I’m sure Jeff can explain better than I can what this does, right So, some Atomic compare and exchange operations might fail when we have unions which have padding bits that don’t participate in the representing that value So, what does that mean? Basically, I took the quote directly out of the C++ 20 Standard, the Draft, where this code is not not guaranteed to ever succeed So, we have a union, let me make this clear This is a copy and paste from the International ISO Standard (audience laughs) I didn’t make up these names So, we have a union called pony, and it has these two beautiful members, celestia, which is a double, initialize to zero, and luna is short I guess she’s a little bit smaller, which has, because it’s a unit, and there’s several padding bits

Whenever we can initialize this, and Atomic, based on instruct, sorry, based on its union type Whenever we try to call compare exchange strong, this function might never succeed because there are several padding bits which don’t participate in the value representation So, if you have any questions, Jeff is sitting right there Sorry And, Michael Spencer is also signed on the proposal This is one of my favorites In case you didn’t know, there are many, many ways to die in C++ It’s actually extremely important to know, especially if you’re trying to write or bust programs You need to understand all the failure or paths that your program might take Additionally, if you’re writing libraries, or all kinds of shared libraries, or binary modules, things like DLLs, and the boundary module, the module boundaries are failure points which you need to understand how things percolate from Many of these paths have some defaults, and some of them might be user defined So, some of the terminators that we have in C++, this is an extremely small subset We have std:: exit, std::abort, std::terminate, signal, and raise, and these are only the C++ standard version There are C versions and several more By the way, they’re not directly related to std::destroy That’s another function A couple years ago, I had to understand what my program is doing So, I started reading the Standard, as we all do I guess, before we go to sleep, right I started plotting out how many ways our program can die I’m not really expecting you to read all the labels I’ll just say that the orange line, that’s normal program termination So, the flaming pest The rest are a representation of all the different functions and what not, I take that back, some of the ways that are more common for leaving the program In fact, after being here at CPPCon, there is one path that I need to add here, although I’m not sure I’ll have to, somebody will have to come up to me and explain, and that’s contract violation So, that doesn’t appear here today Pool requests are welcome Yes – [Man] Is a forward loop that determinant? Cause there’s nothing there Right on 10 of the fork, going up It goes up and around (unintelligible speech in audience) – No, they cross, yeah, it’s the cross I know, yes Yeah, you do, that’s right So, this graph, this only represents C++ 17 or 14 Okay, so 14 (audience laughs) Okay, you know, pool requests are welcome This is a graph This is available on GitHub Anyone can see it there and make changes Right, so now we come to a very, very dark place, The Void (audience laughs) Is there someone there, or maybe not? As I said a very, very lonely place, and it comes from C It’s an incomplete type that cannot actually be instantiated Incompleteness means the void needs special, it’s not actually, although it cannot be instantiated, it’s not the Empty Type It’s actually more like the Unit Type, or I would say a Unit Type because it’s a type that can have only one value Because it can have only one value, then well, we don’t need to specify that value if it’s the same code because we know the value So, if we know a function that returns just one value, basically it’s as if it doesn’t have a return type There’s a proposal to make regular Void, to make Void a regular type so we can actually instantiate Void object, and give it a lot of regular type semantics Because at the moment, incompleteness means that you need special treatments for templates and generic code, I think the very ironic thing is that they are many, many more Unit Types in C++ You expect that okay, how many Unit Types do you need? But, in fact, we already have null ptr and null opt, which are used in different places There are proposals for monostate and none, which are going to the Standard – [Man] Monostate’s already in there – Or, yeah, okay, so I’ll need to look at that reference

Actually, if you want to make an Empty Type, I’m sure you guys will find maybe a different solution, or way to actually instantiate it, but is a type that cannot, I think, be instantiated In functional programming, an absurd function is a function that takes an instant of Void Type, and we took whatever because we can’t actually call this a function because there’s no way to generate the Void So, that’s the Empty Type, but Void, C++ Void is actually a Unit Type That’s an interesting place, and I’m actually looking forward to seeing the regular type proposal goes soon Okay, so (unintelligible speech in audience) You can instantiate the void? (chatter in audience) Okay, okay so talk to me later I need to fix that Actually, most of this, some parts of this stuff is based on a blog post I wrote last Halloween, and most of it is actually based on a blog post I will write on next Halloween So, but Void is new, so I’ll talk to you later, and then we’ll fix it for the blog post So, Voldemort Types These guys, they come from D, I think from Walter Pride He originally named this term Basically, it’s a type that cannot be named outside of the scope it’s declared in However, code outside the scope can still use this type So, I have an example It’s kind of, sounds convoluted, but it’s actually really simple We have a lambda, and we declare some type of Voldemort inside this lambda, and we simply return an instance at this step Now, code outside this lambda must use the auto keyword because there’s no way to name this because it’s not in any scope that’s accessible for me So, we can use auto, but we can use deco type with this unnameable object to actually create another object of this type (audience laughs) (chatter in audience) You can use using, but using is, you’re still giving your name to something that’s unnameable So, you can use using on the deco type So, these are really cool Now, Zombies, okay What happens to an object in scope after it is move-from? This is kind of a loaded question, and I’m sure everyone here has an opinion because we’re getting some kind of empty shell of an object The Standard has one convention about how to do things Some other libraries might have something else So, the Standard says that at least the container should be invalid, but ad specifies the state Or, you could call members that don’t mutate, or don’t require any preconditions There was a long discussion a few years ago about destructive move, and what to do with these objects Again, I think some people here are much more educated about this than I am It’s a very interesting thing to consider if you’re actually adding move semantics to your type So you have to think what happens to your object before it goes out of scope, after it’s being moved from, if the move is not under, for example, under return statements They’re actually totally unrelated to std::decay, which I think is kind of surprising, or maybe not I don’t know, zombies, do they decay or not? Not sure (unintelligible speech in audience) Yeah, I hope Okay, there we go (audience laughs) So, in fact, as Jeff commented, if you’re really, really looking for zombies, all you have to do is go to the Standard because, again, the International ISO C++ Standard, section 20.5.4.3.1, actually has something called zombie names If you go to the index, there are two very clever entries One of them is brains, and they’re names that want to eat your The other one is living dead, name of This is like the Standard’s Crypt This is where standardized and deprecated names go to die, or get buried They’re zombies because they’re not really gone because many of us actually still have to deal with legacy code bases So, if you’re unfortunate enough to have to do with auto ptr, binary function, bind first, random shuffle, and a few other functions, this is only a partial list, then this

is where you’re going to find these functions in the Standard You know, Bjorne said once that there are only two kinds of languages, the ones people complain about and the one nobody uses I think we all love C++, and it’s good to shine a light on some of it So, thank you (audience applauds) However, I do have four minutes and 20 seconds If you want a few more bonus slides or questions (audience yells) I knew it Yes – [Man] So the Void in aggregate, you can still initialize it four, 20 – Yeah, I think that that’s what they mentioned I’ll add that to the, yeah, when I actually get to writing the blog post Okay, Unicorns So, there was a proposal, the Unified Call Syntax proposal, which wanted to allow, when we have the function called f(x,y), if f couldn’t be found, it’s going to try to look for x.f(y) The inverse is not, I’m just gonna run quickly cause I wanted to get to some of the other ones The opposite transformation from a method of a free function, it was not proposed The motivation was things like begin or swap, which today require two different implementations One is like vector.begin, and one is the global.begin If we have that, we can only have one implementation, and it was very controversial Many feared that it might break some legacy code So, at the moment, as far as I know, it’s still stuck, and it’s not in C++ However, yeah, so Jeff wrote this nice little, I just simply had to put this one up I’m just gonna let you read it for a couple of seconds This is valid code, and it does actually run You can see it on Godbolt, right, yeah (chatter in audience) Yeah, okay, so this is an implementation of unicorns So, Demons, yeah We all know and love the notorious, infamous Nasal Demon of Undefined Behavior We all love undefined behavior This is what most of C++, Twitter, and Shafik talk about all day, right, night and day Basically, it renders your entire program meaningless if there is even one undefined behavior situation in your code I think the most annoying thing is that the compiler actively assumes that UB never happens, never, ever happens So, that means that when the compiler gets to a point in your code where you have undefined behavior, it says no, no way There’s no possibility this can happen Then it tries to think up ways of under what conditions this isn’t undefined behavior, and then it will transform your code under this warped logic That’s how you get extremely strange things A couple of years ago, somebody posted a program on Reddit, and then it made it to Twitter for this five line program Let’s just go through it quickly We’re defining a function pointer called function It doesn’t take any arguments, returns an integer, and we define a function pointer of this type as static one on the global name space This is going to get default initialized to zero, right This is all good and well We’re defining and new function called Erase All, which erases your hard drive Okay, this is called Erase All And, another function called Never Called, which assigns Erase All to this global function pointer Our program hasn’t even started yet So, no harm done Then, what does main do? It calls Do But remember, we actually never called Never Called, so Erase All wasn’t ever set to Do, and all we did is call Do However, Do was default initialized to now, and you’re referencing or calling a default initialized function is undefined behavior Chaos ensued You don’t need to know a lot of assembly to understand that just see, at least that particular version with that set of lines actually erases the hard drive So, I think that a lot of people had a lot of fun with that, and some didn’t (audience laughs) Right, so Flying Saucers Oh, I have 10 seconds Spaceship Operator, I’ll skip that I think most of you know this one I think it’s awesome that the default is totally ordered number wise in comparison No need to write any operator Basically just define it equals default, and it’s awesome Shadowing, all of you know since you were five Transparent Objects, too difficult to explain in three seconds That’s the end, right, thank you (audience applauds)