Transcript
Discussion (0)
Hi, my name is Gleb, I live in London and I run a C++ club at work where we discuss
C++ programming news and related articles.
You can find our meeting notes at cppclub.uk.
This podcast and the meeting notes contain public information only.
This is episode 5 for the meeting number 130 that took place on the 3rd of June 2021.
Pure Virtual C++ Conference by Microsoft
Microsoft has published videos of the conference talks.
Of a particular interest is the talk by Gabriel Dos Reis, C++++ modules, year 2021.
After a short introduction to modules,
Gabriel gives an update on the current status of modules in different compilers.
MSVC modules are production-ready.
GCC 11 still in experimental mode.
Clang has a feature branch for module development, which is still in experimental mode. Gabriel expects GCC and Clang has a feature branch for module development which is still in experimental mode.
Gabriel expects GCC and Clang modules to reach production level quality by the end of 2021 or early 2022.
Build tools that support modules include MSBuild production quality
and experimental support is available in CMake, Build2 and Mison.
He mentions the following articles and modules in MSVC.
A tour of C++ modules in Visual Studio.
Walkthrough Build and Import Header Units in Microsoft Visual C++.
Walkthrough Import STLL libraries as header units.
He also lists the following talks on modules
and how to use them.
Gabriel Dos Reis.
Programming with C++ modules.
Guide for the working programmer.
Daniela Engert.
Visibility, reachability, linkage.
The three spices of C++ modules.
Boris Kolpachkov, practical C++ modules.
Gabriel Dos Reis, programming in the large with C++20.
This was a meeting C++ 2020 keynote. I found this one to be very detail-heavy on module interface file
IFC structure and implementation, which could be useful for tool developers, but perhaps not so
much for the ordinary programmer who wants to use modules. As an aside, Gabriel used a concept to
prevent implicit conversion in a function.
There was a function template,
which went like this.
template
angle brackets
std colon colon
same as
angle brackets uint32 underscore t
angle brackets
i, which is the template parameter name.
,
void foo,
open parenthesis,
i,
index,
close parenthesis, and then the function body.
This means that the parameter index must be exactly of type uint32 underscore t,
and not any other type implicitly convertible to uint32-t.
Gabriel talks about the new opportunities for tooling enabled by the new semantic representation
of the code provided by module interface build artifacts. He mentions his disappointment at the
lack of common representation of the module interface across compilers,
and his hope for an eventual convergence onto a common format.
The binary representation IFC that MSVC uses for modules is based on the open-source internal program representation IPR
developed by Gabi and Bjarne Stroustrup 15 years
ago. One thing that came up in the Q&A session after the meeting C++ 2020 keynote was the fact
that the IFC files are compiler setting specific, but I don't remember any mentions of compiler
flags being stored in IFC.
I'm curious if Compilers and Tools will be able to check if an AFC file was built with compatible compiler flags.
Modules present an opportunity to replace the commonly used interface with other languages,
which is currently Xtern C, with something better.
This is of a particular interest to me, as I use SWIG to interface with Java.
SWIG stands for Simplified Wrapper Interface Generator.
And if you have something called simple, it is never that.
Case in point, SOAP.
I would really like to replace SWIG with something modern.
Another interesting thing said in the Q&A session
was the future possibility of embedding IFC in DLLs.
This would provide tools with runtime introspection capability,
much like.NET languages have today.
At the end of the talk, Gabriel asks all the interested developers
to go and try using modules with all the compilers and build tools,
and provide feedback to WG21 and tool developers.
Visibility-reachability linkage, the three spices of C++ modules.
A talk by Daniela Engert.
Daniela has been building software since the late 1970s.
She says,
Folks, I just think we are doing this wrong now.
We follow the book of John.
I mean John Lakers' book about layering software and designing large systems.
End quote.
She explains the drawbacks of the current header-based compilation model.
Macros, ODR violations,
and says that modules allow us to shift the library protection boundary
from the current position between library interface and implementation
to the more natural position between library as a whole and its consuming translation unit. Quote, this is the way, end quote.
A nice call-out to the Mandalorian there.
Daniela goes through C++ name lookup rules and explains how modules allow better control
of name visibility across translation units by using the export qualifier.
She also explains the various types of linkage and how modules affect the picture.
This is a good detailed talk worth your attention.
Modules in managed C++
After the Meeting C++ 2020 keynote, someone asked Gabi if modules were supported in managed C++ or C++ slash CLI.
He said no work has been done in that area.
Module support in MSVC requires std colon C++ latest switch, which requires MSVC standards
compliant mode slash permissive minus This switch enables two-phase lookup, which is not supported with managed C++.
I tried using modules in the Hello World app in Visual Studio 2019.
I created a new Win32 console project that included iostream and wrote
Hello World to std cout. This is a boilerplate generated by Visual Studio
when you create a project like that. It has an include statement which includes
iostream and then int main without parameters
in which there is one line std cout stream out hello world and that's it. Then I went to project settings c++
language and set the following options. C++ language standard. I set it to preview features
from the latest c++ working draft. The switch slashd colon C++ latest
Enable experimental C++ standard library modules
I set it to Yes
and the corresponding switch is
slash experimental colon module
Note that this requires that you select the standard library modules component during Visual Studio installation.
After that I replaced the include statement with import.
Now the first line reads import std.core.
I left the rest alone, and when I did all that, in the currently available Visual Studio 2019 version 16.9.2, which was the currently available version at the time of writing.
The program built and ran successfully. I didn't have to manually tweak the system module paths
like in earlier versions. However, IntelliSense didn't seem to know about modules, the import keyword was highlighted red and stdcout appeared as
an unknown symbol. When I did the above in the latest 2019 version 16.10 preview 4,
everything worked including IntelliSense which didn't flag any errors. Gagneris. Just as I was writing this, Visual Studio 2019 16.10 was released.
The main news was that all C++20 features were now available under the
std colon C++ latest switch. It's the first compiler to be fully C++ 20 compliant.
A Redditor writes
I love that every single time
they put in release notes
that they repaired IntelliSense
for C++ 20 modules.
Then I write a single hello world
program and IntelliSense fails.
End quote.
In my experience with
a hello world program, IntelliSense in the new version seems to work,
as opposed to the previous release, but I haven't used modules properly yet.
Also, Visual Studio 2019 16.11 Preview 1 was released at the same time.
You can visit the announcement page to see lots of pretty
screenshots, lots of improvements in Git support, but I'm probably not going to use them as I prefer
Git command line. Most Git tools hide the crucial details from you and then you end up with some
weird history or a tragic merge you can't get out of. I gave it a go, and IntelliSense works well with modules.
I also tried importing Iostream as a header unit instead of stdcore
into my Hello World program.
And IntelliSense didn't flag any errors, however,
the build failed because the compiler couldn't find the header unit.
A quick aside about MSVC standards
conformance mode compatibility.
Starting with Visual Studio 2017,
which corresponds to MSVC compiler
version 14.1, it is possible to opt
into the standards conformance mode
with the compiler switch permissive-.
Quote, this option dis switch permissive-minus. Quote, this option disables
permissive behaviors and sets the ZC compiler options for strict conformance.
In IDE this option also makes the IntelliSense engine underline non-conforming code.
This is a default mode for new projects created with Visual Studio 2017 version 15.5 and later.
Quote,
Starting in Visual Studio 2019 version 16.8, the std colon C++ latest option implicitly sets the permissive minus option.
It's required for C++20 module support.
The conformant mode requires Windows SDK version 10.0.16299.0
or later, which corresponds to the Windows Fall Creators SDK.
Codenames. Earlier SDK versions do not even compile in conformant mode.
The two-phase lookup is not supported in C++ slash CLI, as I mentioned before.
But also, OpenMP is not compatible with two-phase lookup until VS 2019 version 16.5.
To disable two-phase lookup and leave other conformant behavior enabled,
you can use the switch ZC lowercase colon two-phase minus.
WG21 May 2021 mailing is available. Here are some papers that caught my attention.
Monadic operations for stdoptional. The author Cy Brand of Microsoft writes
quote stdoptional is a very important vocabulary type in C++ 17 and up.
Some users of it can be very verbose and would benefit from operations which allow functional composition.
I propose adding map, end underscore then, and or underscore else member functions to stdoptional
to support this monadic style of programming.
End quote.
Imagine a set of image processing functions that return an image.
To call them in sequence, you would use a series of nested function calls.
For example, if your calling function were called getCuteCat, which took an image as a parameter,
you would call in that function the following functions. Return addRainbow and then inside
makeSmaller and then makeIceSparkle and addBowtie and cropToCat and inside all those you would have
the initial image. Notice how you have to read the calls from the innermost
function call outwards, which isn't very natural. If we want these functions to
return an optional image or an error code, we can use std optional of image
for that. But now we have to check every call's return value so that we don't call
the subsequent functions in if a call returned an error.
This proposal makes it possible to change such function calls,
and handles failures transparently for the entire call chain.
If this was accepted, then the call would look like this.
return CropToCat image
.and then add bowtie..and then make
eyes sparkle. And then.map make smaller. And then.map add rainbow.
This is how optional data type works in other languages. Optional in Swift and
Java. Maybe in Haskell, Agda and Idris
Option in Rust and Scala
According to Cybrand, C++ is the only language that has an optional type without monadic API
Mark all library static cast wrappers as no discard
This paper by Hanna Dusikova is a great
example of a small targeted proposal
that makes sense and fits
on a single page.
Quote. This paper
proposes adding the attribute
no discard to all library
based cast function templates
which only wrap language casts
as they are meaningless without accessing
the resulting value.
End quote.
These templates are toInteger, forward, move, moveIfNoExcept,
as const, toUnderlying, identity, and bitcast.
HANA notes that Microsoft STL already marks these as no discard.
Next paper was Pattern Matching with Exception Handling.
The N plus 1 monster strikes again.
This time it's about using the proposed pattern matching feature with exceptions.
The author, Jared Waterloo, proposes to allow the inspect statement
to catch exceptions without having to use try-catch.
This way, if a function returns a and throws b and c,
the cases of the inspect statement for the function call
would be able to match a, b and c in a uniform way.
Reddit points out many flaws in this proposal.
What happens if the inspected function returns A or variant of A and B,
and also throws A?
Compared with exception handling,
which you can and often should avoid doing for a single function call,
the proposal adds quite a lot of error-checking machinery at
call site.
Some corner cases could also lead to hard-to-find bugs.
As the Redditor Grassicot notes, imagine a function returning variant of a, b, and c
being called using the new inspect statement that has the three cases.
If the function signature changes to return variant of A and B, the inspect statement still
compiles, but now the case C is silently a catch. If you had an enclosing catch C at a higher level,
it won't catch it anymore. The paper seems to miss quite a few important use cases,
and it's not clear if the proposed feature actually improves anything,
while introducing many potential breaks and subtle hard-to-find bugs.
C++ has a Wikipedia page dedicated to criticisms of it.
The first comment on the Reddit thread summarizes it nicely with a Bjarne Stroustrup quote.
There are only two kinds of languages,
the ones people complain about and the ones nobody uses.
End quote.
The article has sections on slow compile times,
Iostream,
well, that's fair,
iterators,
uniform initialization syntax,
exceptions,
encoding of string literals of all things, and code bloat for some old implementations of C++.
Why?
It also links to some articles by authors that seem to have an irrational hate for C++.
I mean, it's just a programming language, you don't have to use it.
Semantics of unsigned integers.
A Redditor asks, what should be the semantics of unsigned integers?
As it often happens, to get the right answer, someone has to post a wrong answer.
And the Redditor FullSpectral was happy to oblige.
They wrote, quote,
I'm one of those that doesn't agree with the always use sign
types thing. If you don't understand
the magnitude of the values involved,
using sign types
isn't going to magically make everything better.
I believe in modeling the things you're
operating on, and if that can never
be negative,
then I don't see how using signed values is better unless you always check the result.
To that Tony Van Erd replied,
People expect numbers to act like numbers.
Neither signed nor unsigned really work like numbers
when you are near the boundaries,
but unsigned puts a boundary at zero which may very well be the most common number in
all programming.
So avoid using unsigned numbers for numbers.
Use signed.
The committee apologizes profusely for making sizeT be unsigned.
Another Redditor wrote, quote,
These are some valid use cases of modular behavior of unsigned arithmetic.
Hashes, random numbers, implementing multi-precision types, cryptography, emulation of hardware,
end quote.
And bit operations operations of course
another redditor
reminded what the C++
core guidelines say about this
in the section
yes.106
don't try to avoid
negative values by using unsigned
quote
the C++ core guidelines also have
the unsigned for bitwise, signed for arithmetic rule.
End quote.
And of course someone mentioned Rust.
Quote, Rust does a better job of divorcing silentness from overflow behavior and what's undefined behavior,
along with avoiding the implicit integer casts and promotions
that make these subtleties problematic.
This is it for today,
and I'll leave you with this tweet by Sarah Dresner,
who describes the ideal development workflow.
Make it work.
Make it right.
Make it fast.
Make it work again because you broke it making it fast.
That's it. Thanks for joining and I'll talk to you next week.
Bye.