hsutter / cppfront
- вторник, 20 сентября 2022 г. в 00:32:29
A personal experimental C++ Syntax 2 -> Syntax 1 compiler
See License
Cppfront is a experimental compiler from a potential C++ 'syntax 2' (Cpp2) to today's 'syntax 1' (Cpp1), to learn some things, prove out some concepts, and share some ideas. This compiler is a work in progress and currently hilariously incomplete... basic functions work, classes will be next, then metaclasses and lightweight exceptions.
.cpp2
file? My goal is to explore whether there's a way we can evolve C++ itself to become 10x simpler, safer, and more toolable. If we had an alternate C++ syntax, it would give us a "bubble of new code that doesn't exist today" where we could make arbitrary improvements (e.g., change defaults, remove unsafe parts, make the language context-free and order-independent, and generally apply 30 years' worth of learnings), free of backward source compatibility constraints.
In 2015-16 I did most of the 'syntax 2' design work. Since then, my ISO C++ evolution proposals and conference talks have come from this work (see list below) — each presenting one part of the design as a standalone proposal under today's syntax, usually with a standalone prototype implementation, to validate and refine that part. Since 2021, I've been writing this cppfront compiler to prototype all the parts together as a whole as originally intended, now including the alternative 'syntax 2' for C++ that enables their full designs including otherwise-breaking changes.
This is one of many experiments going on across the industry looking at ways to accomplish a major C++ evolution. I look forward to seeing how all the experiments work out. This experiment is different in two main ways.
For me, ISO C++ is the best tool in the world today to write the programs I want and need. I want to keep writing code in C++... just "nicer":
with less complexity to remember;
with fewer safety gotchas; and
with the same level of tool support other languages enjoy.
We've been improving C++'s safety and ergonomics with each ISO C++ release, but they have been "10%" improvements. We haven't been able to do a "10x" improvement primarily because we have to keep 100% syntax backward compatibility. So, what if we could have our compatibility cake, and eat it too — by having:
100% seamless link compatibility always (no marshaling, no thunks, no wrappers, no generated 'compatibility modules' to import/export C++ code from/to a different world); and
100% seamless backward source compatibility always available, including 100% SFINAE and macro compatibility, but only pay for it when we use it... that is, apply C++'s familiar "zero-overhead principle" also to backward source compatibility?
In cppfront this means you have two options always available: (1) Write mixed Cpp1/Cpp2 in the same source file with perfect backward source compatibility via #include
or import
. (2) Write only Cpp2 in a particular source file and program in a 10x simpler C++, where code is type-safe and memory-safe by construction, keeps perfect backward link compatibility via import
, and in the future (if this project succeeds) with faster compilers and better tools tuned for the simpler language.
I hope to start a conversation about what could be possible within C++’s own evolution to rejuvenate C++, now that we have C++20 and soon C++23 to build upon. I want to encourage us to look for ways to push the boundaries to bring C++ itself forward and double down on C++ — not to switch to something else. I want us to aim for major C++ evolution directed toward things that will make us better C++ programmers — not programmers of something else.
My specific goal is to explore the question: Can we make C++ 10x safer, simpler, and more toolable? I want each proposed improvement to address those known C++ pain points in a measurable way (e.g., reduce a class of CVEs (vulnerabilities) by A%, reduce the guidance we have to teach by B%).
An alternative syntax would let us do things we can never do within today's syntax without breaking the world:
[[nodiscard]]
the default);import std;
the default);union
and pointer arithmetic);Scores of people have given valuable feedback and many are listed below, but I especially want to thank Joe Duffy, Anders Hejlsberg, Bjarne Stroustrup, Andrew Sutton, Tim Sweeney, and Mads Torgersen for their insights and valuable feedback on this work over the years — especially when they disagreed with me. I'd also like to thank Dave Abrahams, Andrei Alexandrescu, Walter Bright, Lee Howes, Chris McKinsey, Scott Meyers, Gor Nishanov, Andrew Pardoe, Sean Parent, Jared Parsons, David Sankel, Nathan Sidwell, JC van Winkel, and Ville Voutilainen for broad feedback on the design.
Many more people are listed below for their help with specific parts of the design and those proposals/prototypes. I apologize for the names I have forgotten.
cl cppfront.cpp -std:c++20 -EHsc
g++-10 cppfront.cpp -std=c++20 -o cppfront
clang++-12 cppfront.cpp -std=c++20 -o cppfront
.cpp2
file?Run cppfront your.cpp2
, then run the generated your.cpp
through any major C++20 compiler after putting /cppfront/include
in the path so it can find cpp2util.h
.
cl your.cpp -std:c++20 -EHsc
g++-10 your.cpp -std=c++20
clang++-12 your.cpp -std=c++20
I'm not posting much documentation because that would imply this project is intended for others to use — if it someday becomes ready for that, I'll post more docs.
To learn more, please see:
.cpp2
file and the .cpp
file it is translated to. Each filename briefly describes the language features the test demonstrates (e.g., contracts, parameter passing, bounds safety, type-safe is
queries and as
casts, initialization safety, and generalized value capture including in function expressions ('lambdas'), postconditions, and string interpolation).Here are the ISO C++ papers and CppCon conference talks I've given since 2015 that have been derived from this work, in the order that I brought each piece forward. Most of the details in the materials below are still current with only incremental updates, apart from the specific syntax of course.
This is not yet implemented in cppfront. Implementations are shipping in Visual Studio and in CLion, and initial parts have been upstreamed in Clang. I want to especially thank Matthias Gehre, Gabor Horvath, Neil MacIntosh, and Kyle Reed for their help in implementing the Lifetime static analysis design in Visual Studio and a Clang fork. Thanks also to the following for their input and feedback on the specification: Andrei Alexandrescu, Steve Carroll, Pavel Curtis, Gabriel Dos Reis, Joe Duffy, Daniel Frampton, Anna Gringauze, Chris Hawblitzel, Nicolai Josuttis, Ellie Kornstaedt, Aaron Lahman, Ryan McDougall, Nathan Myers, Gor Nishanov, Andrew Pardoe, Jared Parsons, Dave Sielaff, Richard Smith, Jim Springfield, and Bjarne Stroustrup.
This is not yet implemented in cppfront. I welcome a real GC expert to collaborate with on bringing this forward to become a "real" usable tracing GC memory arena that C++ code can opt into, with real C++ zero-overhead costing (don't pay anything if you don't do a gc.new
, and if you do use it then have the costs be proportional to the number of gc.new
allocations).
<=>
This is part of ISO C++20 and C++23. Thank you again to everyone who helped land this in the Standard in C++20 and improve it in C++23, including especially Walter Brown, Lawrence Crowl, Cameron DaCamara, Gabriel Dos Reis, Jens Maurer, Barry Revzin, Richard Smith, and David Stone.
This is not yet implemented in cppfront. Thanks again to Andrew Sutton and his colleagues Wyatt Childers and Jennifer Yao for their help in implementing the Clang-based prototypes of this proposal, and everyone else who contributed feedback on the design including Louis Brandy, Chandler Carruth, Casey Carter, Matúš Chochlík, Lawrence Crowl, Pavel Curtis, Louis Dionne, Gabriel Dos Reis, Joe Duffy, Kenny Kerr, Nicolai Josuttis, Aaron Lahman, Scott Meyers, Axel Naumann, Gor Nishanov, Stephan T. Lavavej, Andrew Pardoe, Sean Parent, Jared Parsons, David Sankel, Richard Smith, Jeff Snyder, Mike Spertus, Mads Torgersen, Daveed Vandevoorde, Tony Van Eerd, JC van Winkel, Ville Voutilainen, and Titus Winters, and many more WG 21 / SG 7 participants.
This is not yet implemented in cppfront.
in
, inout
, out
, move
, and forward
.This is implemented in cppfront, except not the unified operator=
experiment which will come with classes. Thanks to Andrew Sutton for an initial Clang-based implementation.
In 2020 I also started socializing the ideas of:
I had specifically in mind a major C++ evolution's success when many attempts to make C or C++ safer have failed, and the importance of seamless compatibility. The talk was "Bridge to NewThingia," presented at:
is
, as
, and pattern matchingis
and as
".is
and as
is the ISO C++ committee paper.This is partly implemented in cppfront. There is basic support for is
and as
, and very basic inspect
expressions.
Finally, here is a roadmap diagram I made in 2016 that is still recognizably a roadmap of Cpp2's design approach, although a few additions like <=>
came later. I think this is important to show design decisions are related and support each other, so that they are not a gaggle of point fixes but a coordinated refactoring of C++ into a smaller number of regular and combinable features. As Bjarne Stroustrup put it in the ACM History of Programming Languages III (among other places):
"10% the size of C++ in definition and similar in front-end compiler size. ... Most of the simplification would come from generalization." (B. Stroustrup, ACM HOPL-III, 2007; emphasis added)
I haven't updated this roadmap diagram since 2016, but it shows many of the talks and papers that have come since then from this work, and it's still a pretty up-to-date roadmap of the major parts of Cpp2. As of this writing, cppfront implements much of the top part of this roadmap, and I plan for more to follow.
I hope you enjoy reading about this personal experiment, and I hope that it might at least start a conversation about what could be possible within C++'s own evolution to make C++ 10x simpler, safer, and more toolable.