- Joined
- 2/15/22
- Messages
- 1,428
- Points
- 223
Think it's useful at all combined with a state machine or chain of responsibility pattern? Seems clunky.
It all seems less elegant than others. just a random remark.Think it's useful at all combined with a state machine or chain of responsibility pattern? Seems clunky.
But a very poignant one coming from someone with your experience and knowledge I say! They have work to do.It all seems less elegant than others. just a random remark.
I’d be interested in seeing the Rust version.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 understand.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’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.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'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 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.
Feels a bit like that.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.