proxy

Proxy: Next Generation Polymorphism in C++

Proxy-CI

Are you looking to simplify the lifetime management and maintenance of polymorphic objects in C++?

Do you want to write polymorphic code in C++ as easily as in GC languages like Java or C#, without sacrificing performance?

Have you tried other polymorphic programming libraries in C++ but found them deficient?

If so, this library is for you.

Our Mission

“Proxy” is a modern C++ library that helps you use polymorphism (a way to use different types of objects interchangeably) without needing inheritance.

“Proxy” was created by Microsoft engineers and has been used in the Windows operating system since 2022. For many years, using inheritance was the main way to achieve polymorphism in C++. However, new programming languages like Rust offer better ways to do this. We have improved our understanding of object-oriented programming and decided to use pointers in C++ as the foundation for “Proxy”. Specifically, the “Proxy” library is designed to be:

Please refer to the Proxy’s Frequently Asked Questions for more background, and refer to the specifications for more technical details.

Quick Start

“Proxy” is a header-only C++20 library. To use the library, make sure your compiler meets the minimum requirements and just include the header file proxy.h in your source code. Alternatively, you can install the library via vcpkg or conan, by searching for “proxy” (see vcpkg.io and conan.io).

Hello World

Let’s get started with the following “Hello World” example:

#include <iostream>
#include <string>

#include "proxy.h"

struct Streamable : pro::facade_builder
    ::add_convention<pro::operator_dispatch<"<<", true>, std::ostream&(std::ostream& out) const>
    ::build {};

int main() {
  std::string str = "Hello World";
  pro::proxy<Streamable> p1 = &str;
  std::cout << "p1 = " << *p1 << "\n";  // Prints: "p1 = Hello World"

  pro::proxy<Streamable> p2 = std::make_unique<int>(123);
  std::cout << "p2 = " << *p2 << "\n";  // Prints: "p2 = 123"

  pro::proxy<Streamable> p3 = pro::make_proxy<Streamable>(3.14);
  std::cout << "p3 = " << *p3 << "\n";  // Prints: "p3 = 3.14"
}

Here is a step-by-step explanation:

More Expressions

In addition to the operator expressions demonstrated in the previous example, the library supports almost all forms of expressions in C++ and can make them polymorphic. Specifically,

Note that some facilities are provided as macro, because C++ templates today do not support generating a function with an arbitrary name. Here is another example that makes member function call expressions polymorphic:

#include <iostream>
#include <sstream>

#include "proxy.h"

PRO_DEF_MEM_DISPATCH(MemDraw, Draw);
PRO_DEF_MEM_DISPATCH(MemArea, Area);

struct Drawable : pro::facade_builder
    ::add_convention<MemDraw, void(std::ostream& output)>
    ::add_convention<MemArea, double() noexcept>
    ::support_copy<pro::constraint_level::nontrivial>
    ::build {};

class Rectangle {
 public:
  Rectangle(double width, double height) : width_(width), height_(height) {}
  Rectangle(const Rectangle&) = default;

  void Draw(std::ostream& out) const {
    out << "{Rectangle: width = " << width_ << ", height = " << height_ << "}";
  }
  double Area() const noexcept { return width_ * height_; }

 private:
  double width_;
  double height_;
};

std::string PrintDrawableToString(pro::proxy<Drawable> p) {
  std::stringstream result;
  result << "entity = ";
  p->Draw(result);
  result << ", area = " << p->Area();
  return std::move(result).str();
}

int main() {
  pro::proxy<Drawable> p = pro::make_proxy<Drawable, Rectangle>(3, 5);
  std::string str = PrintDrawableToString(p);
  std::cout << str << "\n";  // Prints: "entity = {Rectangle: width = 3, height = 5}, area = 15"
}

Here is a step-by-step explanation:

Other Useful Features

The “Proxy” library is a self-contained solution for runtime polymorphism in C++. There are many other capabilities documented in the specifications. In addition to the features mentioned above, here is a curated list of the most popular features based on user feedback:

Minimum Requirements for Compilers

Family Minimum version Required flags
GCC 11.2 -std=c++20
Clang 15.0.0 -std=c++20
MSVC 19.30 /std:c++20
NVIDIA HPC 24.1 -std=c++20

Build and Run Tests with CMake

git clone https://github.com/microsoft/proxy.git
cd proxy
cmake -B build
cmake --build build -j
ctest --test-dir build -j

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft’s Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies.