
What should go into the C++ standard library (2018) - tim_sw
https://abseil.io/blog/20180227-what-should-go-stdlib
======
pcwalton
I've unfortunately been dragged into some of the conversations around the
proposed 2D graphics library (despite trying to avoid them), and the proposal
is _awful_. It's a mid-'90s vector graphics proposal that is inadequate for
fast GPU-accelerated rendering. A modern library that aimed to be actually
used in the industry would probably look more like WebRender (though
WebRender's API is admittedly a bit of a mess, the principles are sound).
There is no way that browsers or PDF readers or Illustrator or Toon Boom
Harmony or whoever else does vector graphics in industry would ever use the
C++ proposal.

When I brought this up, the proponents of the library dug in their heels and
said that it's not intended for apps like Flash, PDF readers, and browsers,
but rather intended for (a) teaching and (b) for companies that have
prohibitions on using third-party code. The teaching use case (a) is
unconvincing, because while Logo was indeed a good teaching tool and it'd be
great to resurrect it, there's no need to do so in the standard library. As
far as I could tell, the real reason was (b) for the proponents of the spec,
and, needless to say, that's a horrible reason to put something in the
standard library. It's effectively an attempt to route around some random
dysfunctional company policy by saddling _everyone_ with a burden for all
time.

~~~
pjmlp
I am on the other side of the fence.

First because I have found memories for Borland's BGI and there is hardly
something like that for C and C++ that works easily everywhere.

Secondly, because the attacks against the graphics proposal, could be equally
used against iostreams, filesystem or networking.

Not every platform where C++ runs can support them, none of them fully
supports modern OS features and all of them have better third party
alternatives.

Yet for some magic reason it is ok for them to be part of the standard
library, while graphics are not allowed to.

~~~
pcwalton
Plenty of industry applications that need to deal with files use iostream. The
number of apps that would use a bad 2D graphics standard, however, is zero.

~~~
pjmlp
I pretty much doubt that, many apps would be already well served with a BGI
like library.

Plenty of application developers are more than happy with a Swing/GDI like
canvas.

Not everyone needs to be an OpenGL shader guru to draw a couple of lines.

------
borland
He referenced someone wanting to put a 2d graphics library into the standard
library. That seems completely insane.

IMHO, something should be in the standard library if a large class of programs
would want to use it, and if a "lowest common denominator" approach would be
good enough for the majority of those

Example: JSON parsing and generation should be IN. A tremendous number of
programs want to produce and consume JSON, and the bulk of these are not
performance critical and don't have too many edge cases. Just boring normal
JSON.

Example: Sockets should be IN. As above, vast numbers of programs want to use
sockets and a standard approach would suit almost all of them perfectly well.

Example: Graphics should be OUT. A lot of programs could potentially use a
graphics library, but many of these would not be satisfied by a "standard"
approach. Cross platform is the main thing - having to interface with GDI,
SDL, Quartz, and whatever else, and doing a bad job of all of that.

~~~
ioquatix
None of the things you mention really need to be in stdlib. There are plenty
of awesome options, and the great thing is, they all have their own pros/cons
and you can choose depending on your requirements.

The point of C++ is to avoid burdening you with costs you don't want to incur.
Putting this stuff in stdlib is exactly that.

If you could focus on modules and package management that didn't suck, would
you still argue that you need to have JSON and high level sockets in stdlib?

~~~
stochastic_monk
I don’t think C++’s “Pay for what you use” applies here. You don’t have to use
something just because it’s in the standard library. The only practical
difference for a user is a larger binary when statically linking. (The burden
on compiler developers is a very real concern, however.)

------
ndesaulniers
Coming from any language with a package manager to C or C++ is like a trip
back to the dark ages. Sometimes homogeniety is much much better than
flexibility. I too prefer a slimmer std lib with a sane package manager over
batteries included (and kitchen sink, and now outdated gfx api). You might get
shit like leftPad.js, but you'll also get a very very vibrant ecosystem.

~~~
jshap70
You also inherit an entire chain of trust over code you yourself didn't write
nor did anyone actually validate. The issue with leftpad.js wasn't that it was
stupid, it was that it was dangerous.

~~~
flatline
That concern is somewhat orthogonal to the utility of a package manager
itself. If you are using OSS in any way you need to pick and choose what you
take on as a dependency. The package manager solves problems like
distribution, dependency resolution, and discovery. The ease of use may
contribute to poor decision making, which should not be wholly discounted.

~~~
th3l3mons
To piggy back, this also goes down the dependency chain. Leftpad wasn't bad
because it was being used directly. Projects imported other libraries which
either directly pulled leftpad or, more likely, pulled another library which
may be the calling party or not.

------
raphlinus
This makes interesting reading, as I've been following C++ graphics proposals
for a while, and they are one of the inspirations behind piet. I hope for piet
to have a role in the Rust ecosystem similar to what Titus envisions - it's
certainly not a standard, but hopefully will be the tool people reach for,
much like serde is for serialization.

Of course, if I fail, the negative consequences are minor, people just won't
use it. By contrast, having bad stuff in a standard library lasts almost
forever.

------
ioquatix
I completely agree with this article, it is very well written and makes total
sense. Managing dependencies is SO much more important and allows code to move
quickly while existing legacy code sticks with what worked at the time it was
written. There are tons of solutions out there for dependency management for
C++ and a graphics library would be much better as a separate package that can
be versioned, improved, deprecated and ignored as required.

------
jepler
What should go into the C++ standard library? A liberally licensed reference
implementation, where possible. A testsuite, where possible.

("Where possible" would certainly cover all the containers, all the
algorithms, etc; it's less clear how you'd provide a reference implementation
of something that needs to use low level OS functionality for its
implementation, such as 'operator new' or 'ofstream')

Of course, it would also be nice if timely bugfixes went into the C++ standard
library. For instance, std::generate_canonical was standardized in C++11, had
an "issue" lodged in 2015, and the "new specification for
std::generate_canonical" is still awaiting proposed wording (last updated a
year ago, cough, so ... maybe in C++23?)

------
mattnewport
I mostly agree with this article and have been of the opinion for a while that
graphics has no place in the standard library and that what is really needed
is a better cross platform build, packaging and dependency management story.

I would quibble with the hash table example though. I think there is a case to
be made not for changing unordered_map but for adding a new standard hash
table with somewhat different guarantees that make it suitable for higher
performance implementations. Hash tables are so widely useful that a better
standard option without breaking backwards compatibility seems worthwhile.
Other languages have standard libraries that evolve in this way and while it
can get out of hand (looking at you C#) it's a reasonable solution in
moderation.

------
0x8BADF00D
I’ve had many discussions with my coworkers about this. The standard library
is scary to me, completely over engineered. We should be dumping shit from the
standard library that makes no sense (ostream anyone?). Don’t get me started
on iterating over containers. C++20 is shaping up to be the way to hell paved
with good intentions.

~~~
shaklee3
Can you elaborate on iterating over containers? What don't you like?

~~~
0x8BADF00D
Pretty much everything about it is unwieldy. We had std::begin and std::end,
now we have legitimate ranges. It is still difficult to iterate over
customized STL containers, or even generic ones you specify. I’m looking for
something like takeWhile.

------
marcus_holmes
As the title says, put Go in there ;)

Seriously, Go's standard library is the best I've ever used, and would make a
great case study for the "batteries included" case.

But it doesn't have a good story at all around graphics, 2D, 3D or UI. That
doesn't bother gophers much, because the language was(is) intended to build
servers with. But for C++, different story.

------
tmyklebu
Just picking a couple quotes from the article:

> Especially when you compare C++ to other languages, there’s a pretty strong
> argument to be made for a more inclusive and even all-encompassing standard
> library - look at the richness of the standard libraries for Java or Python.

What is that argument? And even if you accept that argument, can we execute?
That is, will the result be at least of a similar quality, or will it be
riddled with subtle gotchas and sharp edges like the existing C++ standard
library?

> So, what should go in the standard library? Fundamentals. Things that can
> only be done with compiler support, or compile-time things that are so
> subtle that only the standard should be trusted to get it right. Vocabulary.
> Time, vector, string. Concurrency. Mutex, future, executors.

Can the standard be trusted to get these things right?

\- Vocabulary: There's a fair amount of depth to what "right" means for vector
and string in many contexts, so the standard can only be trusted to get them
"right" in cases that have very few constraints (where it can do admirably).
Implementors have been known to break the ABIs of std::vector and/or
std::string between compiler/library versions, so they aren't appropriate
types to use in interfaces.

\- Concurrency: Leaving aside the C++ memory model, the library support should
largely be avoided. For an example of why: std::condition_variable's ctor
either takes another condvar or no arguments. pthread_cond_init takes a
pthread_condattr_t. On Linux, this can specify a clock. On my system, if you
want to wait for a second according to
CLOCK_MONOTONIC/std::chrono::steady_clock on my implementation,
condition_variable::wait_until will convert your time to
CLOCK_REALTIME/system_clock (by now()ing both clocks and adding the difference
to the deadline you supplied) and sleep until the converted time. That's not
what you asked for; it's totally wrong and possibly dangerous.

------
maxxxxx
I am little sceptical and also curious about the Graphics library. Is this
meant as a building block for more advanced graphics? Or do you still need to
use things like DirectX if you need speed and features?

~~~
kllrnohj
In terms of the proposal itself it appears to be like an SDL type of thing. It
has a basic way to create an output surface and then draw on it.
Implementations on Windows may opt to do that with Direct2D.

But... it gets a lot of stuff really wrong. Like why does outputsurface have
an "fps" argument on the constructor? What on earth is
io2d::refresh_style::as_fast_as_possible supposed to mean? That doesn't really
map to anything sane. UIs certainly don't behave like that at all, they only
redraw on-demand. Even for a game which does refresh "as fast as possible" it
still does that with its own game loop which will involve more than drawing,
and often pipelined anyway.

Why does rgba_color, even though it's 4 floats, only have a valid range from
0.0 to 1.0 with no mention of color space? It seems like it's supposed to be
linear, but in that case it should be linear extended sRGB, which has a valid
range of -0.5 to 7.5.

Or like you can query for display_dimensions, but _which_ display?

Adding this to a standard would definitely be a huge mistake. It may make a
useful beginners library for just quickly getting up to doodling on the
screen, but that's sort of it. You'd never build an actual shipping product
off of this proposal.

~~~
Reelin
I do agree that this sort of thing doesn't belong in a language standard.

I haven't looked at the proposal myself, but regarding your complaint about
rgba_color float values being on [0.0, 1.0] this is super standard in my
experience. I would expect any well designed API to map [0.0, 1.0] to pixel
values on [0, 255] unless otherwise clearly noted. Color spaces other than raw
pixel values I would expect to be indicated by the name. That's consistent
with at least OpenGL and Java's AWT, but I think also DirectX and most other
APIs.

~~~
kllrnohj
Common, yes, but _wrong_ in ways that increasingly matter. Most APIs that do
[0, 255] are assuming sRGB or they take a color space but can only really
handle slightly-wider colorspaces like DISPLAY_P3.

OpenGL actually works like I said - the float values are not limited to [0.0,
1.0]. There is no clamping in the GPU pipeline, and a transfer function can be
applied to choose between linear & non-linear. For details see extensions like
[https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_...](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_bt2020_linear.txt)
or
[https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_...](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_gl_colorspace_scrgb_linear.txt)

This all matters because there is no longer any platform on which sRGB can be
safely assumed to be the overwhelming majority. Nearly all new flagship mobile
devices are DISPLAY_P3. Nearly all TVs are already some form of HDR, and
desktop monitors are rapidly following suit (Rec. 2020 & 10-bit, so [0, 255]
doesn't even cover enough bits).

So anything graphics that doesn't already work with colorspaces in some way is
basically abandoned or dying, and anything new that doesn't work with them is
going to be DOA.

~~~
Reelin
Apologies, what I wrote wasn't very clear. I didn't mean to imply that an API
should _only_ be able to handle such values, just that a linear color space is
the only sane default in my opinion. And I most certainly didn't mean to imply
that color channels should be limited to only 8 bits, just that it's a very
common default (and often sufficient for simple tasks). As you very rightly
point out, any even semi-modern API absolutely must be able to support the use
of other color spaces when requested.

> Most APIs that do [0, 255] are assuming sRGB

I admit that I've almost exclusively used OpenGL so my impression is far from
expert, but I don't think this is correct. My (admittedly limited) experience
is that a linear color space is assumed unless otherwise specified. In
particular, my understanding is that OpenGL works almost exclusively in a
linear color space except for a few specific sRGB image formats and a few
specific functions. For arbitrary non-linear color spaces I would generally
expect to need to select a backing format of the necessary bit depth, output
linear values, manually apply a conversion function, and then somehow indicate
to the underlying hardware what color space to use when displaying my image
data to the user.

> OpenGL actually works like I said - the float values are not limited to
> [0.0, 1.0].

Agreed, I never meant to imply otherwise. However, do note that when
outputting values from a fragment shader their range (and type) has to match
what the GPU is expecting. So in practice, unless you're using a floating
point image format (such as GL_RGBA32F) your output range is going to be
limited. Personally I almost always use unsigned normalized formats.

> This all matters because there is no longer any platform on which sRGB can
> be safely assumed to be the overwhelming majority.

I'd just like to point out that in principle, a hypothetical API could handle
all programmer interactions in a single color space (eg linear) and then
transparently convert as appropriate for the display device currently in use.
Of course it goes without saying that all conversions must be handled
correctly! Importantly, I'm not trying to claim that such a limited design
would be a good one. Rather, my point is simply that conversions between color
spaces are purely an implementation detail provided you have sufficient bit
depth to work with.

~~~
kllrnohj
> My (admittedly limited) experience is that a linear color space is assumed
> unless otherwise specified.

Non-linear blending is very common. Do a CSS gradient, for example, and it'll
happen in sRGB gamma space not linear space, giving you incorrect results.

Linear _should_ be used more than it is, though, definitely.

> I'd just like to point out that in principle, a hypothetical API could
> handle all programmer interactions in a single color space (eg linear) and
> then transparently convert as appropriate for the display device currently
> in use.

Linear isn't a colorspace. Linear is about the gamma function, which is
independent of the actual colorspace.

sRGB can be both linear & non-linear. In the absence of something specifying
sRGB assumes a non-linear gamma function of 2.2, but it doesn't always. Linear
sRGB is very much A Thing. If you're from the OpenGL world then you may be
thinking of EGL_GL_COLORSPACE_LINEAR_KHR? If so, that's linear sRGB. If you
wanted to output, say, Display_P3, then you need to use
EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT instead.

But you can very much do a single color space. That'd be the linear extended
sRGB I originally talked about, which is float in the range of -.5 to 7.5.
Also called scRGB. Microsoft makes use of this as of Windows Vista.

~~~
Reelin
That CSS gradient example seems like a proper foot gun to me - I don't use CSS
much, and I would _never_ have expected that.

> If you're from the OpenGL world then you may be thinking of
> EGL_GL_COLORSPACE_LINEAR_KHR?

...I've just realized, are you talking about the EGL API (as opposed to
OpenGL)? I don't actually use that - I nearly always restrict myself to an
OpenGL or GLES core profile (no extensions) and use a support library (nearly
always GLFW3) to handle all interfacing with the local system in a platform
independent manner. It just keeps my code sane and manageable. :)

So for me, to output 8-bit non-linear sRGB colors from a fragment shader I
would attach a GL_SRGB8 formatted image to my FBO. Much more typically though
I would simply use GL_RGBA8 and output on the range [0, 1].

> Linear isn't a colorspace. Linear is about the gamma function, which is
> independent of the actual colorspace.

I was very confused by this statement and most of what followed it. After
reading a bit, I think I was conflating color spaces and color models. If I
understand correctly, all along I've been manipulating a linear RGB color
model which was then mapped by my monitor on to (most likely) some
approximation of the sRGB color space. So where I said linear earlier, I
believe what I meant was any linear RGB color model (not space). Bonus points
for using [0, 1] as the interval because it's easy to think about.

What it comes down to is that as a programmer, I just want to get my code
working. Linear models on [0, 1] are easy to process and think about - 0 is
off, 1 is on, and 0.5 is half way in between. If you want to add things
together, you just add them together. Remapping from one range to another is
trivial. It all just works. Sure it doesn't match up with human perception the
way you might expect, but that's what the graphics API, drivers, a color
calibrated display, and possibly some complicated external libraries are for,
right? At least in theory.

~~~
kllrnohj
> ...I've just realized, are you talking about the EGL API (as opposed to
> OpenGL)? I don't actually use that - I nearly always restrict myself to an
> OpenGL or GLES core profile (no extensions) and use a support library
> (nearly always GLFW3) to handle all interfacing with the local system in a
> platform independent manner. It just keeps my code sane and manageable. :)

OpenGL/GLES don't directly do anything with color spaces or gamut. It's part
of the integration with the windowing system that does it. Which in the mobile
usage is typically EGL, but desktop tends to do something else like WGL.

So sounds like you're just punting this decision over to GLFW3, and you're
getting whatever behavior it felt like giving you. Which is probably sRGB or
linear-sRGB.

> What it comes down to is that as a programmer, I just want to get my code
> working. Linear models on [0, 1] are easy to process and think about - 0 is
> off, 1 is on, and 0.5 is half way in between. If you want to add things
> together, you just add them together.

Easy to think about, but also wrong :)

If you want easy, you want linear extended SRGB, aka scRGB. This gives you [0,
1] in the colors you are typically familiar with. And it means when you
display pure white, you're not shoving 1,000 nits into the face of a user with
an HDR monitor. But it means your valid range becomes [-0.5, 7.5] instead.

> a color calibrated display

It doesn't matter how calibrated the display is if the source content isn't
color aware. When you say glClearColor(1.0, 0.0, 0.0, 1.0), which color red is
the display supposed to give you? It'd be broken if it just gave you the
reddest-red it can display, because then your colors will never match when
going between different gamut displays.

Anything that takes a color _must_ also be given a colorspace or have a well-
defined one. Otherwise nothing about color works. And if it's a well-defined
single colorspace, that single colorspace needs to cover the entire visible
spectrum (which extended sRGB does, but something like DCI-P3 doesn't),
otherwise it'll just become obsolete when displays get wider color gamuts.

All the legacy APIs that don't do this just behind your back say "this came
from sRGB colorspace" because that's what used to happen. But anything _new_
shouldn't be doing that, because then it won't work with HDR, wide-gamut
mobile displays, etc... By which I mean "can't display the full range of
colors possible on the display"

~~~
Reelin
I will acknowledge that if we're forced to select only a single color space to
work with, scRGB is an elegant drop in solution due to the value overlap.
However as a developer, I really don't want to be forced to work with 16-bit
color depth in all cases and I'd much rather write algorithms to process data
on the interval [0, 1] due to the reduction in complexity of both thought and
code.

> Easy to think about, but also wrong

Not at all! It's only wrong if there isn't a way to tell the API what color
space the data is in, ie how the data is meant to be interpreted. You keep
describing a _data format_ that is color space aware, while I'm describing an
_API_ that is color space aware coupled with a data format that is generic.

What I'm arguing for here is a clear separation between image data and the
color space used to interpret that data, such that algorithms don't have to be
customized to fit a specific (likely platform dependent) color space. I think
that data storage and manipulation should happen using a simple linear model
such as [0, 1], with a _separate_ mechanism for communicating to the API what
color space the data occupies.

So yes, I do think that a hypothetical clearFrame(1.0, 0.0, 0.0, 1.0) function
call should result in the reddest red possible - _within the currently
configured color space_. Separately, it should be possible to do something
like setColorSpace("AdobeRGB") and thereby _change the meaning_ of (1.0, 0.0,
0.0, 1.0) to the API. Of course the graphics stack and underlying hardware
then have to work together to actually display that data correctly. It could
well be that the display doesn't support the particular color space that was
specified and will need to convert appropriately, but the entire point here is
that the algorithms written by the programmer don't have to be tailored to a
specific color space.

As clearly illustrated by your HDR example, sane defaults are a necessity for
any system. Given the history, it seems that a reasonable API ought to assume
sRGB in lieu of an explicit selection, which it seems they already do for the
most part. Thus in the example you provide, the color (1.0, 0.0, 0.0, 1.0)
would result in a perfectly reasonable shade and intensity of red on _any_
device.

Note that the entire problem of obsolete APIs you refer to is due _entirely_
to making assumptions about which color space the caller is using. The
approach I've described here completely avoids this - you can bolt on new
color spaces later in a clean and fully backwards compatible manner. More than
that, you can even convert _existing APIs_ in a fully backwards compatible
manner because you can reasonably assume that they were already using linear
sRGB unless otherwise specified.

>> a color calibrated display

> It doesn't matter how calibrated the display is if the source content isn't
> color aware.

Well yes, naturally. I was only meaning to note the need for the entire stack
to handle things properly, from driver through to display device. My line of
reasoning was that if your API sends non-linear sRGB data to a display
expecting, for example, linear Adobe RGB data, or if the display isn't color
calibrated in the first place, or ..., then things obviously aren't going to
work correctly. I never meant to imply that my color calibrated display could
read my mind! You say that "Anything that takes a color must also be given a
color space or have a well-defined one.", and I completely agree.

> OpenGL/GLES don't directly do anything with color spaces or gamut.

Actually OpenGL specifically supports the use of non-linear sRGB textures as a
special case. Otherwise though your point is well taken, by default it indeed
operates with colors that occupy a generic linear vector space.

------
mlindner
Making the standard library ever bigger is not a good solution. Self-
standardizing with independent packages is a much better idea. Something like
a graphics library should NEVER go in a standard library.

------
scoutt
I always dreamed with a standardized, cross-platform, cross-arch, (sort of)
automatic, non-blocking, DMA-based memory copying functions (like a special
memcpy) for duplicating or passing big chunks of memory (like for example,
H.264 frames or network packets, from a driver to user space).

------
njbooher
There's enough stuff in it already.

~~~
favorited
There's also some glaring holes. It will be nice to eventually have idiomatic
(and cross-platform) support for networking, filesystem operations, maybe more
modern format strings, etc.

~~~
mlindner
A graphics API is not one of those holes though. Filesystem library already
exists.
[https://en.cppreference.com/w/cpp/filesystem](https://en.cppreference.com/w/cpp/filesystem)

~~~
favorited
Yes, but it is new in C++17 (which a lot of people can't use yet), and I'm not
advocating the graphics proposal specifically.

My point is that you can't just use "the standard library is already really
big" as a justification for not adding new things which make working with the
language much nicer.

~~~
mlindner
I agree for the most part, but we should only really be adding standard
libraries for things that people normally have to fall back to the C standard
library/POSIX code for when writing C++ code. Things like filesystem
operations was one of those. Threading was another. Networking is probably
another. Format strings I would not include in that, though updating the
existing string formatting libraries for the newer C++11 concepts would be a
good idea.

~~~
tmyklebu
Threading was a structurally different change from fs operations and
networking. You need the compiler to cooperate when you're writing to a
location in one thread and reading it from another. You can either get there
using hacks built on escape hatches like 'asm volatile' or by specifying some
semantics for the operation. Specifying a memory model, however imperfect,
means we can move away from the implementation-dependent hacks.

------
forrestthewoods
Sounds like he’s recommending the Rust approach. Seems reasonable.

------
gowld
Why does string need/deserve to be in the standard? Doesn't the existence of
cord cast doubt on thst?

~~~
cmrdporcupine
Back in the dark ages of 1990s C++, it seemed liked every single project had
its own custom string class. Things coalescing around std::string, as
imperfect as it is, is a huge relief.

------
robertkrahn01
Go in the C++ STL! Now that would be a headline!

~~~
userbinator
An unfortunate capitalisation for sure. If "into" and "the" were titlecased,
or "Should" and "Go" lowercased, there would be far less ambiguity.

