• C++ Programming for Financial Engineering
    Highly recommended by thousands of MFE students. Covers essential C++ topics with applications to financial engineering. Learn more Join!
    Python for Finance with Intro to Data Science
    Gain practical understanding of Python to read, understand, and write professional Python code for your first day on the job. Learn more Join!
    An Intuition-Based Options Primer for FE
    Ideal for entry level positions interviews and graduate studies, specializing in options trading arbitrage and options valuation models. Learn more Join!

C++ vs Rust

The following code uses features from C++20 and QN Adv C++ course that uses Concepts
// At this moment I have a vague idea on how I would do it in Rust; is it even worth the effort..

@APalley
@MichaelLewis

C++:
// Test101ActorConcepts.cpp
//
// Simplest example of a system. Context diagram consists only
// of Input and Output systems.
//
// We use C++20 Concepts to replace V1 (outdated) policy-based design (PBD)
//
// Composition
//
//  V2: design using C++20 Concepts
//  V3: V2 + embedded actors
//
// Problem now becomes a pipeline Source -> SUD -> Sink
//
// Summary: this approach is feasible, so worth investigating..
// 1992 .. everything is an object
// 2024 .. everything is an actor
//
// (C) Datasim Education BV 2015-2024
//

#include <string>
#include <iostream>
#include <type_traits>
#include <mutex>
#include <agents.h>

// Interface contract specification
// 1. Each concept is an abstract method
// 2. interface == concept conjunction (e.g. ISUD)

// 1. Define abstract methods (building blocks)
template<typename Message, template <typename Message> class T> // abstract method
    concept ISource = requires (T<Message> x) { x.message(); };
template<typename Message, template <typename Message> class T> // abstract method
    concept ISink = requires (T<Message> x, const Message& s) { x.print(s); };

// 2. Interface relating to context diagram; cojunctional concepts are an alternative
// to multiple inheritance but no danger of fragile base class problem
template< typename Message, template<typename Message> class Input, template<typename Message> class Output>
    concept ISUD = ISource<Message, Input> && ISink<Message, Output>;

// Agent actor-based constraints
template<typename Derived>
    concept IActor1 = std::derived_from<Derived, concurrency::agent>;
template<typename T>
    concept IActor2 = requires (T x) { x.run(); };

// 3. Interface relating to defining constraints pertaining to Actor technology
// https://learn.microsoft.com/en-us/cpp/parallel/concrt/asynchronous-agents-library?view=msvc-170
template<typename Derived>
    concept IActor = IActor1<Derived> && IActor2<Derived>;
  
// The mediator using template template parameter "trick" => can use generic messages
template <typename Message, template <typename Message> class Source, template <typename Message> class Sink>
                requires ISUD<Message, Source, Sink> &&  IActor<Source<Message>> && IActor<Sink<Message>>
    class SUD : public concurrency::agent
{ // SUD is in a chain from Input to Output

private:
    concurrency::ISource<Message>& _source; // formerly known as src
    concurrency::ITarget<Message>& _target; // formerly known as snk
public:
    explicit SUD(concurrency::ISource<Message>& source, concurrency::ITarget<Message>& target)
        : _source(source), _target(target) {}

    void run()
    {
        Message info = concurrency::receive(_source);
        concurrency::send(_target, info);

        done();
    }
};   

// Instance Systems
template <typename Message>
    class MySource : public concurrency::agent
{
    concurrency::ITarget<Message>& _target; // send to SUD
    Message _msg;
public:
    explicit MySource(const Message& msg, concurrency::ITarget<Message>& target)
        : _target(target), _msg(msg) {}

    Message message() const
    {
        // Get data from hardware device
        return Message(_msg);
    }

    void run()
    {
        concurrency::send(_target, message());

        done();
    }

};

template <typename Message>
    class MySink : public concurrency::agent
{
    concurrency::ISource<Message>& _source; // received from SUD
    int _id;
    Message info;
    std::mutex myMutex;
public:
    explicit MySink(concurrency::ISource<Message>& source, int ID = 0) : _source(source), _id(ID) {}
    void print(const Message& s)
    {
        std::lock_guard<std::mutex> guard(myMutex);
        std::cout << "\nin a sink: " << _id << ": " << info << std::endl;
    }

    void run()
    {
        info = concurrency::receive(_source);
        print(info);
        done();
    }

    double compute(int val)
    {
        info *= val*_id;
        return info;
    }
};

int main()
{
    { // Single sink
        using Message = std::string;
        Message m(" good morning");

        // All actors access (read from/write to) a single buffer
        concurrency::overwrite_buffer<Message> buffer;
        MySource i(m, buffer);
        SUD<Message, MySource, MySink> s(buffer, buffer);
        MySink o(buffer);

        i.start(); o.start(); s.start();
        concurrency::agent::wait(&i); concurrency::agent::wait(&s); concurrency::agent::wait(&o);
    }

    {    // Multiple sinks
        using Message = int;
        Message m(23);

        // All actors access (read from/write to) a single buffer
        concurrency::overwrite_buffer<Message> buffer;
        MySource i(m, buffer);
        SUD<Message, MySource, MySink> s(buffer, buffer);
        MySink o1(buffer, 1);
        MySink o2(buffer, 2);
        MySink o3(buffer, 3);
        i.start(); s.start();
        o1.start(); o2.start(); o3.start();
        concurrency::agent::wait(&i); concurrency::agent::wait(&s);
        concurrency::agent::wait(&o1);
        concurrency::agent::wait(&o2);
        concurrency::agent::wait(&o3);

        std::cout << "\ncompute: " << o1.compute(2) << '\n';
        std::cout << "\ncompute: " << o2.compute(2) << '\n';
        std::cout << "\ncompute: " << o3.compute(2) << '\n';
    }

    return 0;
}
I’d be interested in seeing the Rust version.

It seems like most in this thread don’t see Rust as a C++ replacement. But I’d still like to see some comparable programs to make the decision a bit more concrete.
 
I’d be interested in seeing the Rust version.

It seems like most in this thread don’t see Rust as a C++ replacement. But I’d still like to see some comparable programs to make the decision a bit more concrete.
I understand.
Have you tried some examples in Rust?
 
Just out of curiosity, I would be interested in technical (not idiosyncratic, altho' they exist as well) reasons for choosing Rust. I have 35 years C++ exposure and I learned essential Rust in about 5 days. In a sense it is an extreme mini C++.

Channels have potential but they are nowhere near a decent Actor framework IMO.
Maybe the reason: if you are not comfortable with C++, then it might be an option. But its support for OOP and generics is a culture shock. In fairness, it has traits, but then so has C++20 Concepts and more.

I have not seen much on C++ language and Boost library interop.

I could be wrong but at this moment (1st impressions) Rust is a (low-level) systems language. It is unclear to me how it models higher-level abstractions etc.
 
Last edited:
Just out of curiosity, I would be interested in technical (not idiosyncratic, altho' they exist as well) reasons for choosing Rust. I have 35 years C++ exposure and I learned essential Rust in about 5 days. In a sense it is an extreme mini C++.

Channels have potential but they are nowhere near a decent Actor framework IMO.
Maybe the reason: if you are not comfortable with C++, then it might be an option. But its support for OOP and generics is a culture shock. In fairness, it has traits, but then so has C++20 Concepts and more.

I have not seen much on C++ language and Boost library interop.

I could be wrong but at this moment (1st impressions) Rust is a (low-level) systems language. It is unclear to me how it models higher-level abstractions etc.
I’ve never really done systems programming so I can be wrong, but based on your statement, it sounds as though it’s more akin to a C replacement than a C++ one.
 
Last edited:
I’ve never really done systems programming so I can be very wrong in this statement, but based on your statement, it sounds as though it’s more akin to a C replacement than a C++ one.
I'd agree there. We are using it as an essential C replacement for now. Maybe folks will give it a go to create an analytical library with it, but it won't replace C++ in that regard in finance land. Certainly not for many many more decades I'd say.
 
I’ve never really done systems programming so I can be wrong, but based on your statement, it sounds as though it’s more akin to a C replacement than a C++ one.
Feels a bit like that.
Analogy? If a house were built using different languages, then we get a Rust programmer to do the (low-level) plumbing work.
C might be >> Rust?
 
Back
Top